From a0182d0c4cb3d7d27fc136e40f195e722bea0851 Mon Sep 17 00:00:00 2001 From: "ardi@ist-einmalig.de" Date: Mon, 9 Nov 2009 23:03:13 +0000 Subject: [PATCH] * GuiSound stuff rewritten it makes modular * ogg decoder added (old oggplayer removed) * mp3 decoder added (mp3's cane use as backgroundsounds) * WAVE decoder added (but only uncompressed WAVE's) * AIFF decoder added (only uncrompressed) * BNS decoder added all soundformats can use as backgroundsounds dimoks GameSound class removed it is replaced with the new GuiSound stuff * Many small fixes and other changes --- Makefile | 11 +- source/Game_Sound.cpp | 686 ------ source/Game_Sound.h | 49 - source/banner/banner.c | 21 +- source/banner/banner.h | 2 +- source/banner/openingbnr.c | 252 +- source/banner/openingbnr.h | 7 +- source/bannersound.cpp | 209 ++ source/bannersound.h | 6 + source/cheats/cheatmenu.cpp | 8 +- source/homebrewboot/HomebrewBrowse.cpp | 27 +- source/libwiigui/gui.h | 2223 +++++++++--------- source/libwiigui/gui_customoptionbrowser.cpp | 2 +- source/libwiigui/gui_element.cpp | 79 + source/libwiigui/gui_filebrowser.cpp | 6 +- source/libwiigui/gui_gamebrowser.cpp | 2 +- source/libwiigui/gui_gamecarousel.cpp | 4 +- source/libwiigui/gui_gamegrid.cpp | 4 +- source/libwiigui/gui_keyboard.cpp | 4 +- source/libwiigui/gui_optionbrowser.cpp | 5 +- source/libwiigui/gui_searchbar.cpp | 4 +- source/libwiigui/gui_sound.cpp | 507 ++-- source/libwiigui/gui_sound_decoder.h | 111 + source/libwiigui/gui_sound_decoder_aiff.cpp | 165 ++ source/libwiigui/gui_sound_decoder_bns.cpp | 259 ++ source/libwiigui/gui_sound_decoder_mpg.cpp | 214 ++ source/libwiigui/gui_sound_decoder_ogg.cpp | 94 + source/libwiigui/gui_sound_decoder_wav.cpp | 236 ++ source/listfiles.c | 39 +- source/lstub.c | 2 +- source/main.h | 1 - source/menu.cpp | 88 +- source/menu.h | 3 +- source/oggplayer.c | 336 --- source/oggplayer.h | 175 -- source/prompts/DiscBrowser.cpp | 8 +- source/prompts/PromptWindows.cpp | 203 +- source/prompts/TitleBrowser.cpp | 8 +- source/prompts/filebrowser.cpp | 8 +- source/prompts/gameinfo.cpp | 4 +- source/ramdisk/ramdisk.cpp | 25 - source/settings/Settings.cpp | 129 +- source/settings/SettingsPrompts.cpp | 66 +- source/settings/cfg.h | 1 + source/sounds/menuout.ogg | Bin 11143 -> 21077 bytes source/themes/Theme_Downloader.cpp | 24 +- source/usbloader/disc.c | 2 +- source/usbloader/disc.h | 2 +- source/usbloader/wdvd.c | 2 +- source/usbloader/wdvd.h | 2 +- source/wad/wad.cpp | 18 +- 51 files changed, 3388 insertions(+), 2955 deletions(-) delete mode 100644 source/Game_Sound.cpp delete mode 100644 source/Game_Sound.h create mode 100644 source/bannersound.cpp create mode 100644 source/bannersound.h create mode 100644 source/libwiigui/gui_sound_decoder.h create mode 100644 source/libwiigui/gui_sound_decoder_aiff.cpp create mode 100644 source/libwiigui/gui_sound_decoder_bns.cpp create mode 100644 source/libwiigui/gui_sound_decoder_mpg.cpp create mode 100644 source/libwiigui/gui_sound_decoder_ogg.cpp create mode 100644 source/libwiigui/gui_sound_decoder_wav.cpp delete mode 100644 source/oggplayer.c delete mode 100644 source/oggplayer.h diff --git a/Makefile b/Makefile index 509fe603..78e73c7b 100644 --- a/Makefile +++ b/Makefile @@ -35,7 +35,7 @@ LDFLAGS = -g $(MACHDEP) -Wl,-Map,$(notdir $@).map,--section-start,.init=0x80B00 #--------------------------------------------------------------------------------- # any extra libraries we wish to link with the project #--------------------------------------------------------------------------------- -LIBS := -lfat -lpngu -lpng -lm -lz -lwiiuse -lbte -lasnd -logc -lfreetype -ltremor -lmxml -ljpeg +LIBS := -lfat -lpngu -lpng -lm -lz -lwiiuse -lbte -lasnd -logc -lfreetype -ltremor -lmad -lmxml -ljpeg #--------------------------------------------------------------------------------- # list of directories containing libraries, this must be the top level containing # include and lib @@ -67,6 +67,7 @@ TTFFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.ttf))) PNGFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.png))) OGGFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.ogg))) PCMFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.pcm))) +MP3FILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.mp3))) #--------------------------------------------------------------------------------- # use CXX for linking C++ projects, CC for standard C @@ -81,7 +82,7 @@ export OFILES := $(addsuffix .o,$(BINFILES)) \ $(CPPFILES:.cpp=.o) $(CFILES:.c=.o) \ $(sFILES:.s=.o) $(SFILES:.S=.o) \ $(TTFFILES:.ttf=.ttf.o) $(PNGFILES:.png=.png.o) \ - $(OGGFILES:.ogg=.ogg.o) $(PCMFILES:.pcm=.pcm.o) \ + $(OGGFILES:.ogg=.ogg.o) $(PCMFILES:.pcm=.pcm.o) $(MP3FILES:.mp3=.mp3.o) \ $(addsuffix .o,$(ELFFILES)) #--------------------------------------------------------------------------------- @@ -144,7 +145,7 @@ release: #--------------------------------------------------------------------------------- else -DEPENDS := $(OFILES:.o=.d) +DEPENDS := $(OFILES:.o=.d) #--------------------------------------------------------------------------------- # main targets @@ -177,6 +178,10 @@ language: $(wildcard $(PROJECTDIR)/Languages/*.lang) @echo $(notdir $<) $(bin2o) +%.mp3.o : %.mp3 + @echo $(notdir $<) + $(bin2o) + %.certs.o : %.certs @echo $(notdir $<) $(bin2o) diff --git a/source/Game_Sound.cpp b/source/Game_Sound.cpp deleted file mode 100644 index 58db6d85..00000000 --- a/source/Game_Sound.cpp +++ /dev/null @@ -1,686 +0,0 @@ -/*************************************************************************** - * Copyright (C) 2009 - * by Hibernatus - * - * Game_Sound Class by Dimok - * Many other modifications and adjustments by Dimok for USB Loader GX - * - * This software is provided 'as-is', without any express or implied - * warranty. In no event will the authors be held liable for any - * damages arising from the use of this software. - * - * Permission is granted to anyone to use this software for any - * purpose, including commercial applications, and to alter it and - * redistribute it freely, subject to the following restrictions: - * - * 1. The origin of this software must not be misrepresented; you - * must not claim that you wrote the original software. If you use - * this software in a product, an acknowledgment in the product - * documentation would be appreciated but is not required. - * - * 2. Altered source versions must be plainly marked as such, and - * must not be misrepresented as being the original software. - * - * 3. This notice may not be removed or altered from any source - * distribution. - ***************************************************************************/ -#include -#include -#include - -#include "usbloader/disc.h" -#include "usbloader/wbfs.h" -#include "prompts/PromptWindows.h" -#include "libwbfs/libwbfs.h" -#include "language/gettext.h" -#include "Game_Sound.h" - - -#define compare(src, str) ((src && str) ? strncasecmp((const char*) src, (const char *) str, strlen((const char *) str)) : -1) - - -GameSound::GameSound(const u8 * discid) -:GuiSound(NULL, 0, SOUND_PCM) -{ - sound = NULL; - length = 0; - type = SOUND_PCM; - voice = 2; - volume = 100; - loop = false; - freq = 0; - format = 0; - this->LoadSound(discid); -} - -GameSound::~GameSound() -{ - Stop(); - - if(sound) - free(sound); - sound = NULL; -} - -bool GameSound::Play() -{ - Stop(); - - if (!sound || length == 0) - return false; - if (volume == 0) - return true; - - return ASND_SetVoice(voice, format, freq, 0, sound, length, volume, volume, 0) == SND_OK; -} - - -struct IMD5Header -{ - u32 fcc; - u32 filesize; - u8 zeroes[8]; - u8 crypto[16]; -} __attribute__((packed)); - -struct IMETHeader -{ - u8 zeroes[64]; - u32 fcc; - u8 unk[8]; - u32 iconSize; - u32 bannerSize; - u32 soundSize; - u32 flag1; - u8 names[7][84]; - u8 zeroes_2[0x348]; - u8 crypto[16]; -} __attribute__((packed)); - -struct U8Header -{ - u32 fcc; - u32 rootNodeOffset; - u32 headerSize; - u32 dataOffset; - u8 zeroes[16]; -} __attribute__((packed)); - -struct U8Entry -{ - struct - { - u32 fileType : 8; - u32 nameOffset : 24; - }; - u32 fileOffset; - union - { - u32 fileLength; - u32 numEntries; - }; -} __attribute__((packed)); - -struct LZ77Info -{ - u16 length : 4; - u16 offset : 12; -} __attribute__((packed)); - -static char *u8Filename(const U8Entry *fst, int i) -{ - return (char *)(fst + fst[0].numEntries) + fst[i].nameOffset; -} - -struct SWaveHdr -{ - u32 fccRIFF; - u32 size; - u32 fccWAVE; -} __attribute__((packed)); - -struct SWaveFmtChunk -{ - u32 fccFMT; - u32 size; - u16 format; - u16 channels; - u32 freq; - u32 avgBps; - u16 alignment; - u16 bps; -} __attribute__((packed)); - -struct SWaveChunk -{ - u32 fcc; - u32 size; - u8 data; -} __attribute__((packed)); - -struct SAIFFCommChunk -{ - u32 fccCOMM; - u32 size; - u16 channels; - u32 samples; - u16 bps; - u8 freq[10]; -} __attribute__((packed)); - -struct SAIFFSSndChunk -{ - u32 fccSSND; - u32 size; - u32 offset; - u32 blockSize; - u8 data; -} __attribute__((packed)); - -inline u32 le32(u32 i) -{ - return ((i & 0xFF) << 24) | ((i & 0xFF00) << 8) | ((i & 0xFF0000) >> 8) | ((i & 0xFF000000) >> 24); -} - -inline u16 le16(u16 i) -{ - return ((i & 0xFF) << 8) | ((i & 0xFF00) >> 8); -} - -static u8 * uncompressLZ77(const u8 *inputBuf, u32 inputLength, u32 &size) -{ - u8 * buffer = NULL; - if (inputLength <= 0x8 || compare(inputBuf, "LZ77") != 0 || inputBuf[4] != 0x10) - { - return buffer; - } - u32 uncSize = le32(((const u32 *)inputBuf)[1] << 8); - const u8 *inBuf = inputBuf + 8; - const u8 *inBufEnd = inputBuf + inputLength; - buffer = (u8 *) malloc(uncSize); - if (!buffer) - return buffer; - u8 *bufCur = buffer; - u8 *bufEnd = buffer + uncSize; - while (bufCur < bufEnd && inBuf < inBufEnd) - { - u8 flags = *inBuf; - ++inBuf; - for (int i = 0; i < 8 && bufCur < bufEnd && inBuf < inBufEnd; ++i) - { - if ((flags & 0x80) != 0) - { - const LZ77Info &info = *(const LZ77Info *)inBuf; - inBuf += sizeof (LZ77Info); - int length = info.length + 3; - if (bufCur - info.offset - 1 < buffer || bufCur + length > bufEnd) - return buffer; - memcpy(bufCur, bufCur - info.offset - 1, length); - bufCur += length; - } - else - { - *bufCur = *inBuf; - ++inBuf; - ++bufCur; - } - flags <<= 1; - } - } - size = uncSize; - return buffer; -} - -void GameSound::LoadSound(const u8 *discid) -{ - if(!discid) - return; - - if(sound) - free(sound); - sound = NULL; - - Disc_SetUSB(NULL); - wbfs_disc_t *disc = wbfs_open_disc(GetHddInfo(), (u8 *) discid); - if(!disc) - { - WindowPrompt(tr("Can't find disc"), 0, tr("OK")); - return; - } - wiidisc_t *wdisc = wd_open_disc((int (*)(void *, u32, u32, void *))wbfs_disc_read, disc); - if(!wdisc) - { - WindowPrompt(tr("Could not open Disc"), 0, tr("OK")); - return; - } - u32 size = 0; - u8 * snddata = wd_extract_file(wdisc, &size, ALL_PARTITIONS, (char *) "opening.bnr"); - if(!snddata) - { - WindowPrompt(tr("ERROR"), tr("Failed to extract opening.bnr"), tr("OK")); - return; - } - - wd_close_disc(wdisc); - wbfs_close_disc(disc); - - const u8 *soundBin; - const u8 *bnrArc; - const U8Entry *fst; - u32 i; - const u8 *soundChunk; - u32 soundChunkSize; - - const IMETHeader &imetHdr = *(IMETHeader *) snddata; - if (compare(&imetHdr.fcc, "IMET") != 0) - { - WindowPrompt(tr("IMET Header wrong."), 0, tr("OK")); - return; - } - bnrArc = (const u8 *)(&imetHdr + 1); - - const U8Header &bnrArcHdr = *(U8Header *)bnrArc; - - fst = (const U8Entry *)(bnrArc + bnrArcHdr.rootNodeOffset); - for (i = 1; i < fst[0].numEntries; ++i) - if (fst[i].fileType == 0 && strcasecmp(u8Filename(fst, i), "sound.bin") == 0) - break; - if (i >= fst[0].numEntries) - { - return; - } - soundBin = bnrArc + fst[i].fileOffset; - if (compare((&((IMD5Header *)soundBin)->fcc), "IMD5") != 0) - { - WindowPrompt(tr("IMD5 Header not right."), 0, tr("OK")); - return; - } - soundChunk = soundBin + sizeof (IMD5Header); - soundChunkSize = fst[i].fileLength - sizeof (IMD5Header); - if (compare(soundChunk, "LZ77") == 0) - { - u32 uncSize = NULL; - u8 * uncompressed_data = uncompressLZ77(soundChunk, soundChunkSize, uncSize); - if (!uncompressed_data) - { - WindowPrompt(tr("Can't decompress LZ77"), 0, tr("OK")); - return; - } - soundChunk = uncompressed_data; - soundChunkSize = uncSize; - } - - if(compare(soundChunk, "RIFF") == 0) - { - fromWAV(soundChunk, soundChunkSize); - } - else if(compare(soundChunk, "BNS ") == 0) - { - fromBNS(soundChunk, soundChunkSize); - } - else if(compare(soundChunk, "FORM") == 0) - { - fromAIFF(soundChunk, soundChunkSize); - } - - free(snddata); - snddata = NULL; -} - -bool GameSound::fromWAV(const u8 *buffer, u32 size) -{ - const u8 *bufEnd = buffer + size; - const SWaveHdr &hdr = *(SWaveHdr *)buffer; - if (size < sizeof hdr) - return false; - if (compare(&hdr.fccRIFF, "RIFF") != 0) - return false; - if (size < le32(hdr.size) + sizeof hdr.fccRIFF + sizeof hdr.size) - return false; - if (compare(&hdr.fccWAVE, "WAVE") != 0) - return false; - // Find fmt - const SWaveChunk *chunk = (const SWaveChunk *)(buffer + sizeof hdr); - while (&chunk->data < bufEnd && compare(&chunk->fcc, "fmt ") != 0) - chunk = (const SWaveChunk *)(&chunk->data + le32(chunk->size)); - if (&chunk->data >= bufEnd) - return false; - const SWaveFmtChunk &fmtChunk = *(const SWaveFmtChunk *)chunk; - // Check format - if (le16(fmtChunk.format) != 1) - return false; - format = (u8)-1; - if (le16(fmtChunk.channels) == 1 && le16(fmtChunk.bps) == 8 && le16(fmtChunk.alignment) <= 1) - format = VOICE_MONO_8BIT; - else if (le16(fmtChunk.channels) == 1 && le16(fmtChunk.bps) == 16 && le16(fmtChunk.alignment) <= 2) - format = VOICE_MONO_16BIT; - else if (le16(fmtChunk.channels) == 2 && le16(fmtChunk.bps) == 8 && le16(fmtChunk.alignment) <= 2) - format = VOICE_STEREO_8BIT; - else if (le16(fmtChunk.channels) == 2 && le16(fmtChunk.bps) == 16 && le16(fmtChunk.alignment) <= 4) - format = VOICE_STEREO_16BIT; - if (format == (u8)-1) - return false; - freq = le32(fmtChunk.freq); - // Find data - chunk = (const SWaveChunk *)(&chunk->data + le32(chunk->size)); - while (&chunk->data < bufEnd && compare(&chunk->fcc, "data") != 0) - chunk = (const SWaveChunk *)(&chunk->data + le32(chunk->size)); - if (compare(&chunk->fcc, "data") != 0 || &chunk->data + le32(chunk->size) > bufEnd) - return false; - // Data found - sound = (u8 *) malloc(le32(chunk->size)); - if (!sound) - return false; - memcpy(sound, &chunk->data, le32(chunk->size)); - length = le32(chunk->size); - // Endianness - if (le16(fmtChunk.bps) == 16) - for (u32 i = 0; i < length / sizeof (u16); ++i) - ((u16 *) sound)[i] = le16(((u16 *) sound)[i]); - return true; -} - -// ------ -// Copyright (C) 1988-1991 Apple Computer, Inc. -#ifndef HUGE_VAL -# define HUGE_VAL HUGE -#endif - -# define UnsignedToFloat(u) (((double)((long)(u - 2147483647L - 1))) + 2147483648.0) - -double ConvertFromIeeeExtended(const unsigned char* bytes) -{ - double f; - int expon; - unsigned long hiMant, loMant; - - expon = ((bytes[0] & 0x7F) << 8) | (bytes[1] & 0xFF); - hiMant = ((unsigned long)(bytes[2] & 0xFF) << 24) - | ((unsigned long)(bytes[3] & 0xFF) << 16) - | ((unsigned long)(bytes[4] & 0xFF) << 8) - | ((unsigned long)(bytes[5] & 0xFF)); - loMant = ((unsigned long)(bytes[6] & 0xFF) << 24) - | ((unsigned long)(bytes[7] & 0xFF) << 16) - | ((unsigned long)(bytes[8] & 0xFF) << 8) - | ((unsigned long)(bytes[9] & 0xFF)); - - if (expon == 0 && hiMant == 0 && loMant == 0) { - f = 0; - } - else { - if (expon == 0x7FFF) { - f = HUGE_VAL; - } - else { - expon -= 16383; - f = ldexp(UnsignedToFloat(hiMant), expon-=31); - f += ldexp(UnsignedToFloat(loMant), expon-=32); - } - } - - if (bytes[0] & 0x80) - return -f; - else - return f; -} -// ------ - -bool GameSound::fromAIFF(const u8 *buffer, u32 size) -{ - const u8 *bufEnd = buffer + size; - const SWaveHdr &hdr = *(SWaveHdr *)buffer; - if (size < sizeof hdr) - return false; - if (compare(&hdr.fccRIFF, "FORM") != 0) - return false; - if (size < hdr.size + sizeof hdr.fccRIFF + sizeof hdr.size) - return false; - if (compare(&hdr.fccWAVE, "AIFF") != 0) - return false; - // Find fmt - const SWaveChunk *chunk = (const SWaveChunk *)(buffer + sizeof hdr); - while (&chunk->data < bufEnd && compare(&chunk->fcc, "COMM") != 0) - chunk = (const SWaveChunk *)(&chunk->data + chunk->size); - if (&chunk->data >= bufEnd) - return false; - const SAIFFCommChunk &fmtChunk = *(const SAIFFCommChunk *)chunk; - // Check format - format = (u8)-1; - if (le16(fmtChunk.channels) == 1 && fmtChunk.bps == 8) - format = VOICE_MONO_8BIT; - else if (fmtChunk.channels == 1 && fmtChunk.bps == 16) - format = VOICE_MONO_16BIT; - else if (fmtChunk.channels == 2 && fmtChunk.bps == 8) - format = VOICE_STEREO_8BIT; - else if (fmtChunk.channels == 2 && fmtChunk.bps == 16) - format = VOICE_STEREO_16BIT; - if (format == (u8)-1) - return false; - freq = (u32)ConvertFromIeeeExtended(fmtChunk.freq); - // Find data - chunk = (const SWaveChunk *)(&chunk->data + chunk->size); - while (&chunk->data < bufEnd && compare(&chunk->fcc, "SSND") != 0) - chunk = (const SWaveChunk *)(&chunk->data + chunk->size); - if (compare(&chunk->fcc, "SSND") != 0 || &chunk->data + chunk->size > bufEnd) - return false; - // Data found - const SAIFFSSndChunk &dataChunk = *(const SAIFFSSndChunk *)chunk; - sound = (u8 *) malloc(dataChunk.size - 8); - if (!sound) - return false; - memcpy(sound, &dataChunk.data, dataChunk.size - 8); - length = dataChunk.size - 8; - return true; -} - -struct BNSHeader -{ - u32 fccBNS; - u32 magic; - u32 size; - u16 unk1; - u16 unk2; - u32 infoOffset; - u32 infoSize; - u32 dataOffset; - u32 dataSize; -} __attribute__((packed)); - -struct BNSInfo -{ - u32 fccINFO; - u32 size; - u8 codecNum; - u8 loopFlag; - u8 chanCount; - u8 zero; - u16 freq; - u8 pad1[2]; - u32 loopStart; - u32 loopEnd; - u32 offsetToChanStarts; - u8 pad2[4]; - u32 chan1StartOffset; - u32 chan2StartOffset; - u32 chan1Start; - u32 coeff1Offset; - u8 pad3[4]; - u32 chan2Start; - u32 coeff2Offset; - u8 pad4[4]; - s16 coefficients1[8][2]; - u16 chan1Gain; - u16 chan1PredictiveScale; - s16 chan1PrevSamples[2]; - u16 chan1LoopPredictiveScale; - s16 chan1LoopPrevSamples[2]; - u16 chan1LoopPadding; - s16 coefficients2[8][2]; - u16 chan2Gain; - u16 chan2PredictiveScale; - s16 chan2PrevSamples[2]; - u16 chan2LoopPredictiveScale; - s16 chan2LoopPrevSamples[2]; - u16 chan2LoopPadding; -} __attribute__((packed)); - -struct BNSData -{ - u32 fccDATA; - u32 size; - u8 data; -} __attribute__((packed)); - -struct ADPCMByte -{ - s8 sample1 : 4; - s8 sample2 : 4; -} __attribute__((packed)); - -struct BNSADPCMBlock -{ - u8 pad : 1; - u8 coeffIndex : 3; - u8 lshift : 4; - ADPCMByte samples[7]; -} __attribute__((packed)); - -struct BNSDecObj -{ - s16 prevSamples[2]; - s16 coeff[8][2]; -}; - -static void loadBNSInfo(BNSInfo &bnsInfo, const u8 *buffer) -{ - const u8 *ptr = buffer + 8; - bnsInfo = *(const BNSInfo *)buffer; - if (bnsInfo.offsetToChanStarts == 0x18 && bnsInfo.chan1StartOffset == 0x20 && bnsInfo.chan2StartOffset == 0x2C - && bnsInfo.coeff1Offset == 0x38 && bnsInfo.coeff2Offset == 0x68) - return; - bnsInfo.chan1StartOffset = *(const u32 *)(ptr + bnsInfo.offsetToChanStarts); - bnsInfo.chan1Start = *(const u32 *)(ptr + bnsInfo.chan1StartOffset); - bnsInfo.coeff1Offset = *(const u32 *)(ptr + bnsInfo.chan1StartOffset + 4); - if ((u8 *)bnsInfo.coefficients1 != ptr + bnsInfo.coeff1Offset) - memcpy(bnsInfo.coefficients1, ptr + bnsInfo.coeff1Offset, (u8 *)bnsInfo.coefficients2 - (u8 *)&bnsInfo.coefficients1); - if (bnsInfo.chanCount == 2) - { - bnsInfo.chan2StartOffset = *(const u32 *)(ptr + bnsInfo.offsetToChanStarts + 4); - bnsInfo.chan2Start = *(const u32 *)(ptr + bnsInfo.chan2StartOffset); - bnsInfo.coeff2Offset = *(const u32 *)(ptr + bnsInfo.chan2StartOffset + 4); - if ((u8 *)bnsInfo.coefficients2 != ptr + bnsInfo.coeff2Offset) - memcpy(bnsInfo.coefficients2, ptr + bnsInfo.coeff2Offset, (u8 *)bnsInfo.coefficients2 - (u8 *)&bnsInfo.coefficients1); - } -} - -static void decodeADPCMBlock(s16 *buffer, const BNSADPCMBlock &block, BNSDecObj &bnsDec) -{ - int h1 = bnsDec.prevSamples[0]; - int h2 = bnsDec.prevSamples[1]; - int c1 = bnsDec.coeff[block.coeffIndex][0]; - int c2 = bnsDec.coeff[block.coeffIndex][1]; - for (int i = 0; i < 14; ++i) - { - int nibSample = ((i & 1) == 0) ? block.samples[i / 2].sample1 : block.samples[i / 2].sample2; - int sampleDeltaHP = (nibSample << block.lshift) << 11; - int predictedSampleHP = c1 * h1 + c2 * h2; - int sampleHP = predictedSampleHP + sampleDeltaHP; - buffer[i] = std::min(std::max(-32768, (sampleHP + 1024) >> 11), 32767); - h2 = h1; - h1 = buffer[i]; - } - bnsDec.prevSamples[0] = h1; - bnsDec.prevSamples[1] = h2; -} - -static u8 * decodeBNS(u32 &size, const BNSInfo &bnsInfo, const BNSData &bnsData) -{ - static s16 smplBlock[14]; - BNSDecObj decObj; - int numBlocks = (bnsData.size - 8) / 8; - int numSamples = numBlocks * 14; - const BNSADPCMBlock *inputBuf = (const BNSADPCMBlock *)&bnsData.data; - u8 * buffer = (u8 *) malloc(numSamples * sizeof (s16)); - s16 *outputBuf; - - if (!buffer) - return buffer; - memcpy(decObj.coeff, bnsInfo.coefficients1, sizeof decObj.coeff); - memcpy(decObj.prevSamples, bnsInfo.chan1PrevSamples, sizeof decObj.prevSamples); - outputBuf = (s16 *)buffer; - if (bnsInfo.chanCount == 1) - for (int i = 0; i < numBlocks; ++i) - { - decodeADPCMBlock(smplBlock, inputBuf[i], decObj); - memcpy(outputBuf, smplBlock, sizeof smplBlock); - outputBuf += 14; - } - else - { - numBlocks /= 2; - for (int i = 0; i < numBlocks; ++i) - { - decodeADPCMBlock(smplBlock, inputBuf[i], decObj); - for (int j = 0; j < 14; ++j) - outputBuf[j * 2] = smplBlock[j]; - outputBuf += 2 * 14; - } - outputBuf = (s16 *)buffer + 1; - memcpy(decObj.coeff, bnsInfo.coefficients2, sizeof decObj.coeff); - memcpy(decObj.prevSamples, bnsInfo.chan2PrevSamples, sizeof decObj.prevSamples); - for (int i = 0; i < numBlocks; ++i) - { - decodeADPCMBlock(smplBlock, inputBuf[numBlocks + i], decObj); - for (int j = 0; j < 14; ++j) - outputBuf[j * 2] = smplBlock[j]; - outputBuf += 2 * 14; - } - } - size = numSamples * sizeof (s16); - return buffer; -} - -bool GameSound::fromBNS(const u8 *buffer, u32 size) -{ - const BNSHeader &hdr = *(BNSHeader *)buffer; - if (size < sizeof hdr) - return false; - if (compare(&hdr.fccBNS, "BNS ") != 0) - return false; - // Find info and data - BNSInfo infoChunk; - loadBNSInfo(infoChunk, buffer + hdr.infoOffset); - const BNSData &dataChunk = *(const BNSData *)(buffer + hdr.dataOffset); - // Check sizes - if (size < hdr.size || size < hdr.infoOffset + hdr.infoSize || size < hdr.dataOffset + hdr.dataSize - || hdr.infoSize < 0x60 || hdr.dataSize < sizeof dataChunk - || infoChunk.size != hdr.infoSize || dataChunk.size != hdr.dataSize) - return false; - // Check format - if (infoChunk.codecNum != 0) // Only codec i've found : 0 = ADPCM. Maybe there's also 1 and 2 for PCM 8 or 16 bits ? - return false; - format = (u8)-1; - if (infoChunk.chanCount == 1 && infoChunk.codecNum == 0) - format = VOICE_MONO_16BIT; - else if (infoChunk.chanCount == 2 && infoChunk.codecNum == 0) - format = VOICE_STEREO_16BIT; - if (format == (u8)-1) - return false; - freq = infoChunk.freq; - // Copy data - if (infoChunk.codecNum == 0) - { - sound = decodeBNS(length, infoChunk, dataChunk); - if (!sound) - return false; - } - else - { - sound = (u8*) malloc(dataChunk.size); - if (!sound) - return false; - memcpy(sound, &dataChunk.data, dataChunk.size); - length = dataChunk.size; - } - return true; -} diff --git a/source/Game_Sound.h b/source/Game_Sound.h deleted file mode 100644 index 82092b31..00000000 --- a/source/Game_Sound.h +++ /dev/null @@ -1,49 +0,0 @@ -/*************************************************************************** - * Copyright (C) 2009 - * by Hibernatus - * - * Game_Sound Class by Dimok - * Many other modifications and adjustments by Dimok for USB Loader GX - * - * This software is provided 'as-is', without any express or implied - * warranty. In no event will the authors be held liable for any - * damages arising from the use of this software. - * - * Permission is granted to anyone to use this software for any - * purpose, including commercial applications, and to alter it and - * redistribute it freely, subject to the following restrictions: - * - * 1. The origin of this software must not be misrepresented; you - * must not claim that you wrote the original software. If you use - * this software in a product, an acknowledgment in the product - * documentation would be appreciated but is not required. - * - * 2. Altered source versions must be plainly marked as such, and - * must not be misrepresented as being the original software. - * - * 3. This notice may not be removed or altered from any source - * distribution. - ***************************************************************************/ - #ifndef _GAMESOUND_H_ -#define _GAMESOUND_H_ - -#include "libwiigui/gui.h" - -class GameSound : public GuiSound -{ - public: - GameSound(const u8 * discid); - ~GameSound(); - void LoadSound(const u8 *discid); - bool Play(); - bool fromWAV(const u8 *buffer, u32 size); - bool fromAIFF(const u8 *buffer, u32 size); - bool fromBNS(const u8 *buffer, u32 size); - private: - u8 * sound; - u32 length; - u32 freq; - u8 format; -}; - -#endif diff --git a/source/banner/banner.c b/source/banner/banner.c index c3ee55cb..ffcea164 100644 --- a/source/banner/banner.c +++ b/source/banner/banner.c @@ -22,11 +22,11 @@ #include "patches/fst.h" #include "usbloader/fstfile.h" -s32 dump_banner(const char * discid,const char * dest) +s32 dump_banner(const u8* discid,const char * dest) { // Mount the disc //Disc_SetWBFS(1, (u8*)discid); - Disc_SetUSB((u8*)discid); + Disc_SetUSB(discid); Disc_Open(); @@ -108,16 +108,17 @@ s32 dump_banner(const char * discid,const char * dest) if (ret < 0) return ret; + WDVD_Reset(); + WDVD_ClosePartition(); //fatInitDefault(); //SDCard_Init(); - - FILE *fp = NULL; - fp = fopen(dest, "wb"); - - fwrite(banner, 1, fst[index].filelen, fp); - - fclose(fp); - + WDVD_SetUSBMode(NULL); + FILE *fp = fopen(dest, "wb"); + if(fp) + { + fwrite(banner, 1, fst[index].filelen, fp); + fclose(fp); + } free(fstbuffer); free(banner); diff --git a/source/banner/banner.h b/source/banner/banner.h index 58ce995e..b6254713 100644 --- a/source/banner/banner.h +++ b/source/banner/banner.h @@ -13,7 +13,7 @@ extern "C" { #endif -s32 dump_banner(const char * discid,const char * dest); +s32 dump_banner(const u8 *discid,const char * dest); #ifdef __cplusplus } diff --git a/source/banner/openingbnr.c b/source/banner/openingbnr.c index 536b781b..e0694968 100644 --- a/source/banner/openingbnr.c +++ b/source/banner/openingbnr.c @@ -24,6 +24,9 @@ #include "MD5.h" #include "banner.h" +#include "openingbnr.h" +#include "../ramdisk/ramdisk.h" +#include "../listfiles.h" u16 be16(const u8 *p) { @@ -68,7 +71,6 @@ void md5(u8 *data, u32 len, u8 *hash) MD5(hash, data, len); } -static FILE *fp; typedef struct { u8 zeroes[0x40]; @@ -113,13 +115,18 @@ typedef struct u8 zeroes[16]; } U8_archive_header; -static void write_file(void* data, size_t size, char* name) +static int write_file(void* data, size_t size, char* name) { + size_t written=0; FILE *out; out = fopen(name, "wb"); - fwrite(data, 1, size, out); - fclose(out); -} + if(out) + { + written = fwrite(data, 1, size, out); + fclose(out); + } + return (written == size) ? 1 : -1; +} u8* decompress_lz77(u8 *data, size_t data_size, size_t* decompressed_size) { @@ -233,7 +240,7 @@ static int write_imd5_lz77(u8* data, size_t size, char* outname) return 0; } -static int do_U8_archive(void) +static int do_U8_archive(FILE *fp) { U8_archive_header header; U8_node root_node; @@ -325,19 +332,19 @@ static int do_U8_archive(void) return 0; } -static void do_imet_header(void) +static void do_imet_header(FILE *fp) { - imet_data_t header; + imet_data_t header; fread(&header, 1, sizeof header, fp); - write_file(&header, sizeof(header), "header.imet"); + write_file(&header, sizeof(header), "header.imet"); } void do_U8_archivebanner(FILE *fp) { - U8_archive_header header; - U8_node root_node; + U8_archive_header header; + U8_node root_node; u32 tag; u32 num_nodes; U8_node* nodes; @@ -347,119 +354,176 @@ void do_U8_archivebanner(FILE *fp) u32 data_offset; u16 dir_stack[16]; int dir_index = 0; - + fread(&header, 1, sizeof header, fp); tag = be32((u8*) &header.tag); if (tag != 0x55AA382D) { //printf("No U8 tag"); exit(0); } - + fread(&root_node, 1, sizeof(root_node), fp); num_nodes = be32((u8*) &root_node.size) - 1; printf("Number of files: %d\n", num_nodes); - + nodes = malloc(sizeof(U8_node) * (num_nodes)); fread(nodes, 1, num_nodes * sizeof(U8_node), fp); - + data_offset = be32((u8*) &header.data_offset); rest_size = data_offset - sizeof(header) - (num_nodes+1)*sizeof(U8_node); - + string_table = malloc(rest_size); fread(string_table, 1, rest_size, fp); - + for (i = 0; i < num_nodes; i++) { - U8_node* node = &nodes[i]; - u16 type = be16((u8*)&node->type); - u16 name_offset = be16((u8*)&node->name_offset); - u32 my_data_offset = be32((u8*)&node->data_offset); - u32 size = be32((u8*)&node->size); - char* name = (char*) &string_table[name_offset]; - u8* file_data; - - if (type == 0x0100) { - // Directory - mkdir(name, 0777); - chdir(name); - dir_stack[++dir_index] = size; - //printf("%*s%s/\n", dir_index, "", name); - } else { - // Normal file - - if (type != 0x0000) { - printf("Unknown type"); - exit(0); - } - - fseek(fp, my_data_offset, SEEK_SET); - file_data = malloc(size); - fread(file_data, 1, size, fp); - write_file(file_data, size, name); - free(file_data); - //printf("%*s %s (%d bytes)\n", dir_index, "", name, size); - } - - while (dir_stack[dir_index] == i+2 && dir_index > 0) { - chdir(".."); - dir_index--; - } + U8_node* node = &nodes[i]; + u16 type = be16((u8*)&node->type); + u16 name_offset = be16((u8*)&node->name_offset); + u32 my_data_offset = be32((u8*)&node->data_offset); + u32 size = be32((u8*)&node->size); + char* name = (char*) &string_table[name_offset]; + u8* file_data; + + if (type == 0x0100) { + // Directory + mkdir(name, 0777); + chdir(name); + dir_stack[++dir_index] = size; + //printf("%*s%s/\n", dir_index, "", name); + } else { + // Normal file + + if (type != 0x0000) { + printf("Unknown type"); + exit(0); + } + + fseek(fp, my_data_offset, SEEK_SET); + file_data = malloc(size); + fread(file_data, 1, size, fp); + write_file(file_data, size, name); + free(file_data); + //printf("%*s %s (%d bytes)\n", dir_index, "", name, size); + } + + while (dir_stack[dir_index] == i+2 && dir_index > 0) { + chdir(".."); + dir_index--; + } } free(string_table); } int extractbnrfile(const char * filepath, const char * destpath) { - int ret; + int ret = -1; + FILE *fp = fopen(filepath, "rb"); + if(fp) + { + subfoldercreate(destpath); + chdir(destpath); - fp = fopen(filepath, "rb"); - - mkdir(destpath, 0777); - chdir(destpath); - - do_imet_header(); - ret = do_U8_archive(); - - fclose(fp); + do_imet_header(fp); + ret = do_U8_archive(fp); + fclose(fp); + } return ret; } int unpackBin(const char * filename,const char * outdir) { -FILE *fp; -fp = fopen(filename,"rb"); + FILE *fp = fopen(filename,"rb");; + if(fp) + { + subfoldercreate(outdir); + chdir(outdir); -if(fp!=NULL) + do_U8_archivebanner(fp); + fclose(fp); + return 1; + } + return 0; +} + +#define TMP_PATH(s) "BANNER:/dump"s +//#define TMP_PATH(s) "SD:/dump"s + +int unpackBanner(const u8 *gameid, int what, const char *outdir) { -mkdir(outdir, 0777); -chdir(outdir); -do_U8_archivebanner(fp); -fclose(fp); -return 1; -} -return 0; -} - -int unpackBanner(char * gameid, char * outdir) -{ -s32 ret = dump_banner(gameid,"SD:/opening.bnr"); -if (ret != 1) return -1; - -ret = extractbnrfile("SD:/opening.bnr","SD:/neu"); -if (ret != 0) return -1; -remove("SD:/opening.bnr"); -char iconpath[60]; -snprintf(iconpath,sizeof(iconpath),"%s/meta/icon.bin",outdir); -ret = unpackBin(iconpath,"SD:/icon"); -if (ret != 1) return -1; - -if (unlink("/neu/meta/banner.bin") == -1) return -1; -if (unlink("/neu/meta/icon.bin") == -1) return -1; -if (unlink("/neu/meta/sound.bin") == -1) return -1; -if (unlink("/neu/header.imet") == -1) return -1; -if (unlink("/neu/meta") == -1) return -1; -if (unlink("/neu") == -1) return -1; - -return 1; + char path[256]; + if(!ramdiskMount("BANNER", NULL)) return -1; + + subfoldercreate(TMP_PATH("/")); + s32 ret = dump_banner(gameid, TMP_PATH("/opening.bnr")); + if (ret != 1) + { + ret = -1; + goto error2; + } + + ret = extractbnrfile(TMP_PATH("/opening.bnr"), TMP_PATH("/")); + if (ret != 0) + { + ret = -1; + goto error2; + } + + if(what & UNPACK_BANNER_BIN) + { + snprintf(path, sizeof(path),"%sbanner/", outdir); + ret = unpackBin(TMP_PATH("/meta/banner.bin"), path); + if (ret != 1) + { + ret = -1; + goto error2; + } + } + if(what & UNPACK_ICON_BIN) + { + snprintf(path, sizeof(path),"%sicon/", outdir); + ret = unpackBin(TMP_PATH("/meta/icon.bin"), path); + if (ret != 1) + { + ret = -1; + goto error2; + } + } + if(what & UNPACK_SOUND_BIN) + { + snprintf(path, sizeof(path),"%ssound.bin", outdir); + FILE *fp = fopen(TMP_PATH("/meta/sound.bin"), "rb"); + if(fp) + { + size_t size; + u8 *data; + fseek(fp, 0, SEEK_END); + size = ftell(fp); + if(!size) + { + ret = -1; + goto error; + } + fseek(fp, 0, SEEK_SET); + data = (u8 *)malloc(size); + if(!data) + { + ret = -1; + goto error; + } + if(fread(data, 1, size, fp) != size) + { + ret = -1; + goto error; + } + ret = write_file(data, size, path); + } +error: fclose(fp); + } + ramdiskUnmount("BANNER"); +error2: + if(ret < 0) + return ret; + return 1; } diff --git a/source/banner/openingbnr.h b/source/banner/openingbnr.h index 5b29cbeb..3142fba0 100644 --- a/source/banner/openingbnr.h +++ b/source/banner/openingbnr.h @@ -29,8 +29,11 @@ extern "C" //! Files extracted: banner.bin icon.bin and sound.bin int extractbnrfile(const char * filepath, const char * destpath); int unpackBin(const char * filename,const char * outdir); -//int unpackBanner(const char * filename,const char * outdir); -int unpackBanner(const char * gameid, const char * outdir); +#define UNPACK_BANNER_BIN 1 /* extract banner.bin to outdir/banner/ */ +#define UNPACK_ICON_BIN 2 /* extract icon.bin to outdir/icon/ */ +#define UNPACK_SOUND_BIN 4 /* copies sound.bin to outdir/sound.bin */ +#define UNPACK_ALL (UNPACK_SOUND_BIN | UNPACK_ICON_BIN | UNPACK_BANNER_BIN) +int unpackBanner(const u8 * gameid, int what, const char *outdir); //! Extract the lz77 compressed banner, icon and sound .bin u8* decompress_lz77(u8 *data, size_t data_size, size_t* decompressed_size); diff --git a/source/bannersound.cpp b/source/bannersound.cpp new file mode 100644 index 00000000..06ad48e4 --- /dev/null +++ b/source/bannersound.cpp @@ -0,0 +1,209 @@ +#include +#include +#include +#include + +#include "usbloader/disc.h" +#include "usbloader/wbfs.h" +#include "prompts/PromptWindows.h" +#include "libwbfs/libwbfs.h" +#include "language/gettext.h" +#include "bannersound.h" + + +struct IMD5Header +{ + u32 fcc; + u32 filesize; + u8 zeroes[8]; + u8 crypto[16]; +} __attribute__((packed)); + +struct IMETHeader +{ + u8 zeroes[64]; + u32 fcc; + u8 unk[8]; + u32 iconSize; + u32 bannerSize; + u32 soundSize; + u32 flag1; + u8 names[7][84]; + u8 zeroes_2[0x348]; + u8 crypto[16]; +} __attribute__((packed)); + +struct U8Header +{ + u32 fcc; + u32 rootNodeOffset; + u32 headerSize; + u32 dataOffset; + u8 zeroes[16]; +} __attribute__((packed)); + +struct U8Entry +{ + struct + { + u32 fileType : 8; + u32 nameOffset : 24; + }; + u32 fileOffset; + union + { + u32 fileLength; + u32 numEntries; + }; +} __attribute__((packed)); + +struct LZ77Info +{ + u16 length : 4; + u16 offset : 12; +} __attribute__((packed)); + +static char *u8Filename(const U8Entry *fst, int i) +{ + return (char *)(fst + fst[0].numEntries) + fst[i].nameOffset; +} + +inline u32 le32(u32 i) +{ + return ((i & 0xFF) << 24) | ((i & 0xFF00) << 8) | ((i & 0xFF0000) >> 8) | ((i & 0xFF000000) >> 24); +} + +inline u16 le16(u16 i) +{ + return ((i & 0xFF) << 8) | ((i & 0xFF00) >> 8); +} + +static u8 *uncompressLZ77(const u8 *inBuf, u32 inLength, u32 &size) +{ + u8 *buffer = NULL; + if (inLength <= 0x8 || *((const u32 *)inBuf) != 0x4C5A3737 /*"LZ77"*/ || inBuf[4] != 0x10) + return NULL; + u32 uncSize = le32(((const u32 *)inBuf)[1] << 8); + + const u8 *inBufEnd = inBuf + inLength; + inBuf += 8; + buffer = new(std::nothrow) u8[uncSize]; + if (!buffer) + return buffer; + + u8 *bufCur = buffer; + u8 *bufEnd = buffer + uncSize; + + while (bufCur < bufEnd && inBuf < inBufEnd) + { + u8 flags = *inBuf; + ++inBuf; + for (int i = 0; i < 8 && bufCur < bufEnd && inBuf < inBufEnd; ++i) + { + if ((flags & 0x80) != 0) + { + const LZ77Info &info = *(const LZ77Info *)inBuf; + inBuf += sizeof (LZ77Info); + int length = info.length + 3; + if (bufCur - info.offset - 1 < buffer || bufCur + length > bufEnd) + return buffer; + memcpy(bufCur, bufCur - info.offset - 1, length); + bufCur += length; + } + else + { + *bufCur = *inBuf; + ++inBuf; + ++bufCur; + } + flags <<= 1; + } + } + size = uncSize; + return buffer; +} + +const u8 *LoadBannerSound(const u8 *discid, u32 *size) +{ + if(!discid) + return NULL; + + Disc_SetUSB(NULL); + wbfs_disc_t *disc = wbfs_open_disc(GetHddInfo(), (u8 *) discid); + if(!disc) + { + WindowPrompt(tr("Can't find disc"), 0, tr("OK")); + return NULL; + } + wiidisc_t *wdisc = wd_open_disc((int (*)(void *, u32, u32, void *))wbfs_disc_read, disc); + if(!wdisc) + { + WindowPrompt(tr("Could not open Disc"), 0, tr("OK")); + return NULL; + } + u32 opening_bnr_size = 0; + u8 * opening_bnr = wd_extract_file(wdisc, &opening_bnr_size, ALL_PARTITIONS, (char *) "opening.bnr"); + if(!opening_bnr) + { + WindowPrompt(tr("ERROR"), tr("Failed to extract opening.bnr"), tr("OK")); + return NULL; + } + + wd_close_disc(wdisc); + wbfs_close_disc(disc); + + const U8Entry *fst; + + const IMETHeader *imetHdr = (IMETHeader *)opening_bnr; + if ( imetHdr->fcc != 0x494D4554 /*"IMET"*/ ) + { + WindowPrompt(tr("IMET Header wrong."), 0, tr("OK")); + free(opening_bnr); + return NULL; + } + const U8Header *bnrArcHdr = (U8Header *)(imetHdr + 1); + + fst = (const U8Entry *)( ((const u8 *)bnrArcHdr) + bnrArcHdr->rootNodeOffset); + u32 i; + for (i = 1; i < fst[0].numEntries; ++i) + if (fst[i].fileType == 0 && strcasecmp(u8Filename(fst, i), "sound.bin") == 0) + break; + if (i >= fst[0].numEntries) + { + WindowPrompt(tr("sound.bin not found."), 0, tr("OK")); + free(opening_bnr); + return NULL; + } + const u8 *sound_bin = ((const u8 *)bnrArcHdr) + fst[i].fileOffset; + if ( ((IMD5Header *)sound_bin)->fcc != 0x494D4435 /*"IMD5"*/ ) + { + WindowPrompt(tr("IMD5 Header not right."), 0, tr("OK")); + free(opening_bnr); + return NULL; + } + const u8 *soundChunk = sound_bin + sizeof (IMD5Header);; + u32 soundChunkSize = fst[i].fileLength - sizeof (IMD5Header); + + if ( *((u32*)soundChunk) == 0x4C5A3737 /*"LZ77"*/ ) + { + u32 uncSize = NULL; + u8 * uncompressed_data = uncompressLZ77(soundChunk, soundChunkSize, uncSize); + if (!uncompressed_data) + { + WindowPrompt(tr("Can't decompress LZ77"), 0, tr("OK")); + free(opening_bnr); + return NULL; + } + if(size) *size=uncSize; + free(opening_bnr); + return uncompressed_data; + } + u8 *out = new(std::nothrow) u8[soundChunkSize]; + if(out) + { + memcpy(out, soundChunk, soundChunkSize); + if(size) *size=soundChunkSize; + } + free(opening_bnr); + return out; +} diff --git a/source/bannersound.h b/source/bannersound.h new file mode 100644 index 00000000..6cf7b526 --- /dev/null +++ b/source/bannersound.h @@ -0,0 +1,6 @@ +#ifndef BANNERSOUND_H +#define BANNERSOUND_H + +const u8 *LoadBannerSound(const u8 *discid, u32 *size); + +#endif /* BANNERSOUND_H */ diff --git a/source/cheats/cheatmenu.cpp b/source/cheats/cheatmenu.cpp index ccb3f5a6..64e40fa8 100644 --- a/source/cheats/cheatmenu.cpp +++ b/source/cheats/cheatmenu.cpp @@ -28,7 +28,9 @@ int CheatMenu(const char * gameID) { bool exit = false; int ret = 1; - GuiSound btnClick(button_click2_pcm, button_click2_pcm_size, SOUND_PCM, Settings.sfxvolume); + // because destroy GuiSound must wait while sound playing is finished, we use a global sound + if(!btnClick2) btnClick2=new GuiSound(button_click2_pcm, button_click2_pcm_size, Settings.sfxvolume); + // GuiSound btnClick(button_click2_pcm, button_click2_pcm_size, Settings.sfxvolume); char imgPath[100]; snprintf(imgPath, sizeof(imgPath), "%sbutton_dialogue_box.png", CFG.theme_path); @@ -45,14 +47,14 @@ int CheatMenu(const char * gameID) { GuiText backBtnTxt(tr("Back") , 22, THEME.prompttext); backBtnTxt.SetMaxWidth(btnOutline.GetWidth()-30); GuiImage backBtnImg(&btnOutline); - GuiButton backBtn(&backBtnImg,&backBtnImg, 2, 3, -140, 400, &trigA, NULL, &btnClick,1); + GuiButton backBtn(&backBtnImg,&backBtnImg, 2, 3, -140, 400, &trigA, NULL, btnClick2,1); backBtn.SetLabel(&backBtnTxt); backBtn.SetTrigger(&trigB); GuiText createBtnTxt(tr("Create") , 22, THEME.prompttext); createBtnTxt.SetMaxWidth(btnOutline.GetWidth()-30); GuiImage createBtnImg(&btnOutline); - GuiButton createBtn(&createBtnImg,&createBtnImg, 2, 3, 160, 400, &trigA, NULL, &btnClick,1); + GuiButton createBtn(&createBtnImg,&createBtnImg, 2, 3, 160, 400, &trigA, NULL, btnClick2,1); createBtn.SetLabel(&createBtnTxt); char txtfilename[55]; diff --git a/source/homebrewboot/HomebrewBrowse.cpp b/source/homebrewboot/HomebrewBrowse.cpp index c066689e..66a13b97 100644 --- a/source/homebrewboot/HomebrewBrowse.cpp +++ b/source/homebrewboot/HomebrewBrowse.cpp @@ -84,9 +84,11 @@ int MenuHomebrewBrowse() { int slidedirection = FADE; /*** Sound Variables ***/ - GuiSound btnSoundOver(button_over_pcm, button_over_pcm_size, SOUND_PCM, Settings.sfxvolume); - GuiSound btnClick(button_click2_pcm, button_click2_pcm_size, SOUND_PCM, Settings.sfxvolume); - GuiSound btnClick1(button_click_pcm, button_click_pcm_size, SOUND_PCM, Settings.sfxvolume); + GuiSound btnSoundOver(button_over_pcm, button_over_pcm_size, Settings.sfxvolume); + // because destroy GuiSound must wait while sound playing is finished, we use a global sound + if(!btnClick2) btnClick2=new GuiSound(button_click2_pcm, button_click2_pcm_size, Settings.sfxvolume); + // GuiSound btnClick(button_click2_pcm, button_click2_pcm_size, Settings.sfxvolume); + GuiSound btnClick1(button_click_pcm, button_click_pcm_size, Settings.sfxvolume); /*** Image Variables ***/ char imgPath[150]; @@ -153,7 +155,7 @@ int MenuHomebrewBrowse() { backBtnTxt.SetWidescreen(CFG.widescreen); backBtnImg.SetWidescreen(CFG.widescreen); } - GuiButton backBtn(&backBtnImg,&backBtnImg, 2, 3, -180, 400, &trigA, &btnSoundOver, &btnClick,1); + GuiButton backBtn(&backBtnImg,&backBtnImg, 2, 3, -180, 400, &trigA, &btnSoundOver, btnClick2,1); backBtn.SetLabel(&backBtnTxt); backBtn.SetTrigger(&trigB); @@ -166,7 +168,7 @@ int MenuHomebrewBrowse() { GoLeftBtn.SetPosition(25, -25); GoLeftBtn.SetImage(&GoLeftImg); GoLeftBtn.SetSoundOver(&btnSoundOver); - GoLeftBtn.SetSoundClick(&btnClick); + GoLeftBtn.SetSoundClick(btnClick2); GoLeftBtn.SetEffectGrow(); GoLeftBtn.SetTrigger(&trigA); GoLeftBtn.SetTrigger(&trigL); @@ -178,7 +180,7 @@ int MenuHomebrewBrowse() { GoRightBtn.SetPosition(-25, -25); GoRightBtn.SetImage(&GoRightImg); GoRightBtn.SetSoundOver(&btnSoundOver); - GoRightBtn.SetSoundClick(&btnClick); + GoRightBtn.SetSoundClick(btnClick2); GoRightBtn.SetEffectGrow(); GoRightBtn.SetTrigger(&trigA); GoRightBtn.SetTrigger(&trigR); @@ -315,7 +317,7 @@ int MenuHomebrewBrowse() { channelBtn.SetPosition(440, 400); channelBtn.SetImage(&channelBtnImg); channelBtn.SetSoundOver(&btnSoundOver); - channelBtn.SetSoundClick(&btnClick); + channelBtn.SetSoundClick(btnClick2); channelBtn.SetEffectGrow(); channelBtn.SetTrigger(&trigA); @@ -766,16 +768,9 @@ int MenuHomebrewBrowse() { else if (homo.GetState() == STATE_CLICKED) { cfg_save_global(); - s32 thetimeofbg = bgMusic->GetPlayTime(); - bgMusic->Stop(); + bgMusic->Pause(); choice = WindowExitPrompt(tr("Exit USB Loader GX?"),0, tr("Back to Loader"),tr("Wii Menu"),tr("Back"),0); - if (!strcmp("", Settings.oggload_path) || !strcmp("notset", Settings.ogg_path)) { - bgMusic->Play(); - } else { - bgMusic->PlayOggFile(Settings.ogg_path); - } - bgMusic->SetPlayTime(thetimeofbg); - SetVolumeOgg(255*(Settings.volume/100.0)); + bgMusic->Resume(); if (choice == 3) { Sys_LoadMenu(); // Back to System Menu diff --git a/source/libwiigui/gui.h b/source/libwiigui/gui.h index 50d9e1fe..d7c4008c 100644 --- a/source/libwiigui/gui.h +++ b/source/libwiigui/gui.h @@ -1,1114 +1,1127 @@ -/*!\mainpage libwiigui Documentation - * - * \section Introduction - * libwiigui is a GUI library for the Wii, created to help structure the - * design of a complicated GUI interface, and to enable an author to create - * a sophisticated, feature-rich GUI. It was originally conceived and written - * after I started to design a GUI for Snes9x GX, and found libwiisprite and - * GRRLIB inadequate for the purpose. It uses GX for drawing, and makes use - * of PNGU for displaying images and FreeTypeGX for text. It was designed to - * be flexible and is easy to modify - don't be afraid to change the way it - * works or expand it to suit your GUI's purposes! If you do, and you think - * your changes might benefit others, please share them so they might be - * added to the project! - * - * \section Quickstart - * Start from the supplied template example. For more advanced uses, see the - * source code for Snes9x GX, FCE Ultra GX, and Visual Boy Advance GX. - - * \section Contact - * If you have any suggestions for the library or documentation, or want to - * contribute, please visit the libwiigui website: - - * http://code.google.com/p/libwiigui/ - * \section Credits - * This library was wholly designed and written by Tantric. Thanks to the - * authors of PNGU and FreeTypeGX, of which this library makes use. Thanks - * also to the authors of GRRLIB and libwiisprite for laying the foundations. - * -*/ - -#ifndef LIBWIIGUI_H -#define LIBWIIGUI_H - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "pngu/pngu.h" -#include "FreeTypeGX.h" -#include "video.h" -#include "filelist.h" -#include "input.h" -#include "oggplayer.h" - -extern FreeTypeGX *fontSystem; - -#define SCROLL_INITIAL_DELAY 20 -#define SCROLL_LOOP_DELAY 3 -#define PAGESIZE 9 -#define FILEBROWSERSIZE 8 -#define MAX_OPTIONS 170 - -typedef void (*UpdateCallback)(void * e); - -enum -{ - ALIGN_LEFT, - ALIGN_RIGHT, - ALIGN_CENTRE, - ALIGN_TOP, - ALIGN_BOTTOM, - ALIGN_MIDDLE -}; -#define ALIGN_CENTER ALIGN_CENTRE -enum -{ - STATE_DEFAULT, - STATE_SELECTED, - STATE_CLICKED, - STATE_HELD, - STATE_DISABLED -}; - -enum -{ - SOUND_PCM, - SOUND_OGG -}; - -enum -{ - IMAGE_TEXTURE, - IMAGE_COLOR, - IMAGE_DATA, - IMAGE_COPY -}; - -enum -{ - TRIGGER_SIMPLE, - TRIGGER_HELD, - TRIGGER_BUTTON_ONLY, - TRIGGER_BUTTON_ONLY_IN_FOCUS -}; - -typedef struct _paddata { - u16 btns_d; - u16 btns_u; - u16 btns_h; - s8 stickX; - s8 stickY; - s8 substickX; - s8 substickY; - u8 triggerL; - u8 triggerR; -} PADData; - -#define EFFECT_SLIDE_TOP 1 -#define EFFECT_SLIDE_BOTTOM 2 -#define EFFECT_SLIDE_RIGHT 4 -#define EFFECT_SLIDE_LEFT 8 -#define EFFECT_SLIDE_IN 16 -#define EFFECT_SLIDE_OUT 32 -#define EFFECT_FADE 64 -#define EFFECT_SCALE 128 -#define EFFECT_COLOR_TRANSITION 256 -#define EFFECT_PULSE 512 -#define EFFECT_ROCK_VERTICLE 1024 -#define EFFECT_GOROUND 2048 - - -//!Sound conversion and playback. A wrapper for other sound libraries - ASND, libmad, ltremor, etc -class GuiSound -{ - public: - //!Constructor - //!\param s Pointer to the sound data - //!\param l Length of sound data - //!\param t Sound format type (SOUND_PCM or SOUND_OGG) - GuiSound(const u8 * s, int l, int t); - GuiSound(const u8 * s, int l, int t, int v); - //!Destructor - ~GuiSound(); - //!Start sound playback - void Play(); - //!Start sound playback from ogg file - int PlayOggFile(char * path); - //!Stop sound playback - void Stop(); - //!Pause sound playback - void Pause(); - //!Resume sound playback - void Resume(); - //!Checks if the sound is currently playing - //!\return true if sound is playing, false otherwise - bool IsPlaying(); - //!Set sound volume - //!\param v Sound volume (0-100) - void SetVolume(int v); - //!Set the sound to loop playback (only applies to OGG) - //!\param l Loop (true to loop) - void SetLoop(bool l); - //!Get the playing time in ms for that moment (only applies to OGG) - s32 GetPlayTime(); - //!Set the starting point or playtime for skipping (only applies to OGG) - //!\param time in ms - void SetPlayTime(s32 time); - protected: - const u8 * sound; //!< Pointer to the sound data - int type; //!< Sound format type (SOUND_PCM or SOUND_OGG) - s32 length; //!< Length of sound data - s32 voice; //!< Currently assigned ASND voice channel - s32 volume; //!< Sound volume (0-100) - bool loop; //!< Loop sound playback -}; - -//!Menu input trigger management. Determine if action is neccessary based on input data by comparing controller input data to a specific trigger element. -class GuiTrigger -{ - public: - //!Constructor - GuiTrigger(); - //!Destructor - ~GuiTrigger(); - //!Sets a simple trigger. Requires: element is selected, and trigger button is pressed - //!\param ch Controller channel number - //!\param wiibtns Wii controller trigger button(s) - classic controller buttons are considered separately - //!\param gcbtns GameCube controller trigger button(s) - void SetSimpleTrigger(s32 ch, u32 wiibtns, u16 gcbtns); - //!Sets a held trigger. Requires: element is selected, and trigger button is pressed - //!\param ch Controller channel number - //!\param wiibtns Wii controller trigger button(s) - classic controller buttons are considered separately - //!\param gcbtns GameCube controller trigger button(s) - void SetHeldTrigger(s32 ch, u32 wiibtns, u16 gcbtns); - //!Sets a button-only trigger. Requires: Trigger button is pressed - //!\param ch Controller channel number - //!\param wiibtns Wii controller trigger button(s) - classic controller buttons are considered separately - //!\param gcbtns GameCube controller trigger button(s) - void SetButtonOnlyTrigger(s32 ch, u32 wiibtns, u16 gcbtns); - //!Sets a button-only trigger. Requires: trigger button is pressed and parent window of element is in focus - //!\param ch Controller channel number - //!\param wiibtns Wii controller trigger button(s) - classic controller buttons are considered separately - //!\param gcbtns GameCube controller trigger button(s) - void SetButtonOnlyInFocusTrigger(s32 ch, u32 wiibtns, u16 gcbtns); - //!Get X/Y value from Wii Joystick (classic, nunchuk) input - //!\param right Controller stick (left = 0, right = 1) - //!\param axis Controller stick axis (x-axis = 0, y-axis = 1) - //!\return Stick value - s8 WPAD_Stick(u8 right, int axis); - //!Move menu selection left (via pad/joystick). Allows scroll delay and button overriding - //!\return true if selection should be moved left, false otherwise - bool Left(); - //!Move menu selection right (via pad/joystick). Allows scroll delay and button overriding - //!\return true if selection should be moved right, false otherwise - bool Right(); - //!Move menu selection up (via pad/joystick). Allows scroll delay and button overriding - //!\return true if selection should be moved up, false otherwise - bool Up(); - //!Move menu selection down (via pad/joystick). Allows scroll delay and button overriding - //!\return true if selection should be moved down, false otherwise - bool Down(); - - u8 type; //!< trigger type (TRIGGER_SIMPLE, TRIGGER_HELD, TRIGGER_BUTTON_ONLY, TRIGGER_BUTTON_ONLY_IN_FOCUS) - s32 chan; //!< Trigger controller channel (0-3, -1 for all) - WPADData wpad; //!< Wii controller trigger data - PADData pad; //!< GameCube controller trigger data -}; - -extern GuiTrigger userInput[4]; - -//!Primary GUI class. Most other classes inherit from this class. -class GuiElement -{ - public: - //!Constructor - GuiElement(); - //!Destructor - ~GuiElement(); - //!Set the element's parent - //!\param e Pointer to parent element - void SetParent(GuiElement * e); - //!Gets the element's parent - //!\return Pointer to parent element - GuiElement * GetParent(); - //!Gets the current leftmost coordinate of the element - //!Considers horizontal alignment, x offset, width, and parent element's GetLeft() / GetWidth() values - //!\return left coordinate - int GetLeft(); - //!Gets the current topmost coordinate of the element - //!Considers vertical alignment, y offset, height, and parent element's GetTop() / GetHeight() values - //!\return top coordinate - int GetTop(); - //!Sets the minimum y offset of the element - //!\param y Y offset - void SetMinY(int y); - //!Gets the minimum y offset of the element - //!\return Minimum Y offset - int GetMinY(); - //!Sets the maximum y offset of the element - //!\param y Y offset - void SetMaxY(int y); - //!Gets the maximum y offset of the element - //!\return Maximum Y offset - int GetMaxY(); - //!Sets the minimum x offset of the element - //!\param x X offset - void SetMinX(int x); - //!Gets the minimum x offset of the element - //!\return Minimum X offset - int GetMinX(); - //!Sets the maximum x offset of the element - //!\param x X offset - void SetMaxX(int x); - //!Gets the maximum x offset of the element - //!\return Maximum X offset - int GetMaxX(); - //!Gets the current width of the element. Does not currently consider the scale - //!\return width - int GetWidth(); - //!Gets the height of the element. Does not currently consider the scale - //!\return height - int GetHeight(); - //!Sets the size (width/height) of the element - //!\param w Width of element - //!\param h Height of element - void SetSize(int w, int h); - //!Checks whether or not the element is visible - //!\return true if visible, false otherwise - bool IsVisible(); - //!Checks whether or not the element is selectable - //!\return true if selectable, false otherwise - bool IsSelectable(); - //!Checks whether or not the element is clickable - //!\return true if clickable, false otherwise - bool IsClickable(); - //!Checks whether or not the element is holdable - //!\return true if holdable, false otherwise - bool IsHoldable(); - //!Sets whether or not the element is selectable - //!\param s Selectable - void SetSelectable(bool s); - //!Sets whether or not the element is clickable - //!\param c Clickable - void SetClickable(bool c); - //!Sets whether or not the element is holdable - //!\param c Holdable - void SetHoldable(bool d); - //!Gets the element's current state - //!\return state - int GetState(); - //!Gets the controller channel that last changed the element's state - //!\return Channel number (0-3, -1 = no channel) - int GetStateChan(); - //!Sets the element's alpha value - //!\param a alpha value - void SetAlpha(int a); - //!Gets the element's alpha value - //!Considers alpha, alphaDyn, and the parent element's GetAlpha() value - //!\return alpha - int GetAlpha(); - //!Gets the element's AngleDyn value - //!\return alpha - float GetAngleDyn(); - //!Sets the element's scale - //!\param s scale (1 is 100%) - void SetScale(float s); - //!Gets the element's current scale - //!Considers scale, scaleDyn, and the parent element's GetScale() value - virtual float GetScale(); - //!Set a new GuiTrigger for the element - //!\param t Pointer to GuiTrigger - void SetTrigger(GuiTrigger * t); - //!\overload - //!\param i Index of trigger array to set - //!\param t Pointer to GuiTrigger - void SetTrigger(u8 i, GuiTrigger * t); - //!Remove GuiTrigger for the element - //!\param i Index of trigger array to set - void RemoveTrigger(u8 i); - //!Checks whether rumble was requested by the element - //!\return true is rumble was requested, false otherwise - bool Rumble(); - //!Sets whether or not the element is requesting a rumble event - //!\param r true if requesting rumble, false if not - void SetRumble(bool r); - //!Set an effect for the element - //!\param e Effect to enable - //!\param a Amount of the effect (usage varies on effect) - //!\param t Target amount of the effect (usage varies on effect) - void SetEffect(int e, int a, int t=0); - //!This SetEffect is for EFFECT_GOROUND only - //!\param e Effect to enable - //!\param speed is for Circlespeed - //!\param circles Circleamount in degree ike 180 for 1/2 circle or 720 for 2 circles - //!\param r Circle Radius in pixel - //!\param startdegree Degree where to start circling - //!\param anglespeedset Set the speed of Angle rotating make 1 for same speed as Circlespeed +/*!\mainpage libwiigui Documentation + * + * \section Introduction + * libwiigui is a GUI library for the Wii, created to help structure the + * design of a complicated GUI interface, and to enable an author to create + * a sophisticated, feature-rich GUI. It was originally conceived and written + * after I started to design a GUI for Snes9x GX, and found libwiisprite and + * GRRLIB inadequate for the purpose. It uses GX for drawing, and makes use + * of PNGU for displaying images and FreeTypeGX for text. It was designed to + * be flexible and is easy to modify - don't be afraid to change the way it + * works or expand it to suit your GUI's purposes! If you do, and you think + * your changes might benefit others, please share them so they might be + * added to the project! + * + * \section Quickstart + * Start from the supplied template example. For more advanced uses, see the + * source code for Snes9x GX, FCE Ultra GX, and Visual Boy Advance GX. + + * \section Contact + * If you have any suggestions for the library or documentation, or want to + * contribute, please visit the libwiigui website: + + * http://code.google.com/p/libwiigui/ + * \section Credits + * This library was wholly designed and written by Tantric. Thanks to the + * authors of PNGU and FreeTypeGX, of which this library makes use. Thanks + * also to the authors of GRRLIB and libwiisprite for laying the foundations. + * +*/ + +#ifndef LIBWIIGUI_H +#define LIBWIIGUI_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "pngu/pngu.h" +#include "FreeTypeGX.h" +#include "video.h" +#include "filelist.h" +#include "input.h" + +extern FreeTypeGX *fontSystem; + +#define SCROLL_INITIAL_DELAY 20 +#define SCROLL_LOOP_DELAY 3 +#define PAGESIZE 9 +#define FILEBROWSERSIZE 8 +#define MAX_OPTIONS 170 + +typedef void (*UpdateCallback)(void * e); + +enum +{ + ALIGN_LEFT, + ALIGN_RIGHT, + ALIGN_CENTRE, + ALIGN_TOP, + ALIGN_BOTTOM, + ALIGN_MIDDLE +}; +#define ALIGN_CENTER ALIGN_CENTRE +enum +{ + STATE_DEFAULT, + STATE_SELECTED, + STATE_CLICKED, + STATE_HELD, + STATE_DISABLED +}; + +enum +{ + IMAGE_TEXTURE, + IMAGE_COLOR, + IMAGE_DATA, + IMAGE_COPY +}; + +enum +{ + TRIGGER_SIMPLE, + TRIGGER_HELD, + TRIGGER_BUTTON_ONLY, + TRIGGER_BUTTON_ONLY_IN_FOCUS +}; + +typedef struct _paddata { + u16 btns_d; + u16 btns_u; + u16 btns_h; + s8 stickX; + s8 stickY; + s8 substickX; + s8 substickY; + u8 triggerL; + u8 triggerR; +} PADData; + +#define EFFECT_SLIDE_TOP 1 +#define EFFECT_SLIDE_BOTTOM 2 +#define EFFECT_SLIDE_RIGHT 4 +#define EFFECT_SLIDE_LEFT 8 +#define EFFECT_SLIDE_IN 16 +#define EFFECT_SLIDE_OUT 32 +#define EFFECT_FADE 64 +#define EFFECT_SCALE 128 +#define EFFECT_COLOR_TRANSITION 256 +#define EFFECT_PULSE 512 +#define EFFECT_ROCK_VERTICLE 1024 +#define EFFECT_GOROUND 2048 + +#define MAX_SND_VOICES 16 +#define newGuiSound +#define verynewGuiSound + +class GuiSoundDecoder; +class GuiSound +{ + public: + //!Constructor + //!\param s Pointer to the sound data + //!\param l Length of sound data + //!\param v Sound volume (0-100) + //!\param r RAW PCM Sound, when no decoder is found then try to play as raw-pcm + //!\param a true--> Pointer to the sound data is allocated with new u8[...] + //!\ GuiSound will be destroy the buffer if it no more needed + //!\ false-> sound data buffer has to live just as long as GuiSound + GuiSound(const u8 *s, int l, int v=100, bool r=true, bool a=false); + //!Constructor + //!\param p Path to the sound data + //!\param v Sound volume (0-100) + GuiSound(const char *p, int v=100); + //!Load - stop playing and load the new sound data + //! if load not failed replace the current with new sound data + //! otherwise the current date will not changed + //!\params same as by Constructors + //!\return true ok / false = failed + bool Load(const u8 *s, int l, bool r=false, bool a=false); + bool Load(const char *p); + //!Destructor + ~GuiSound(); + + //!Start sound playback + void Play(); + //!Stop sound playback + void Stop(); + //!Pause sound playback + void Pause(); + //!Resume sound playback + void Resume(); + //!Checks if the sound is currently playing + //!\return true if sound is playing, false otherwise + bool IsPlaying(); + //!Set sound volume + //!\param v Sound volume (0-100) + void SetVolume(int v); + //!Set the sound to loop playback (only applies to OGG) + //!\param l Loop (true to loop) + void SetLoop(bool l); + //!Get the playing time in ms for that moment (only applies to OGG) + protected: + s32 voice; // used asnd-voice + u8 *play_buffer[3]; // trpple-playbuffer + int buffer_nr; // current playbuffer + int buffer_pos; // current idx to write in buffer + bool buffer_ready; // buffer is filled and ready + bool buffer_eof; // no mor datas - will stop playing + bool loop; // play looped + s32 volume; // volume + GuiSoundDecoder *decoder; + + void DecoderCallback(); + void PlayerCallback(); + friend void *GuiSoundDecoderThread(void *args); + friend void GuiSoundPlayerCallback(s32 Voice); +}; + +//!Menu input trigger management. Determine if action is neccessary based on input data by comparing controller input data to a specific trigger element. +class GuiTrigger +{ + public: + //!Constructor + GuiTrigger(); + //!Destructor + ~GuiTrigger(); + //!Sets a simple trigger. Requires: element is selected, and trigger button is pressed + //!\param ch Controller channel number + //!\param wiibtns Wii controller trigger button(s) - classic controller buttons are considered separately + //!\param gcbtns GameCube controller trigger button(s) + void SetSimpleTrigger(s32 ch, u32 wiibtns, u16 gcbtns); + //!Sets a held trigger. Requires: element is selected, and trigger button is pressed + //!\param ch Controller channel number + //!\param wiibtns Wii controller trigger button(s) - classic controller buttons are considered separately + //!\param gcbtns GameCube controller trigger button(s) + void SetHeldTrigger(s32 ch, u32 wiibtns, u16 gcbtns); + //!Sets a button-only trigger. Requires: Trigger button is pressed + //!\param ch Controller channel number + //!\param wiibtns Wii controller trigger button(s) - classic controller buttons are considered separately + //!\param gcbtns GameCube controller trigger button(s) + void SetButtonOnlyTrigger(s32 ch, u32 wiibtns, u16 gcbtns); + //!Sets a button-only trigger. Requires: trigger button is pressed and parent window of element is in focus + //!\param ch Controller channel number + //!\param wiibtns Wii controller trigger button(s) - classic controller buttons are considered separately + //!\param gcbtns GameCube controller trigger button(s) + void SetButtonOnlyInFocusTrigger(s32 ch, u32 wiibtns, u16 gcbtns); + //!Get X/Y value from Wii Joystick (classic, nunchuk) input + //!\param right Controller stick (left = 0, right = 1) + //!\param axis Controller stick axis (x-axis = 0, y-axis = 1) + //!\return Stick value + s8 WPAD_Stick(u8 right, int axis); + //!Move menu selection left (via pad/joystick). Allows scroll delay and button overriding + //!\return true if selection should be moved left, false otherwise + bool Left(); + //!Move menu selection right (via pad/joystick). Allows scroll delay and button overriding + //!\return true if selection should be moved right, false otherwise + bool Right(); + //!Move menu selection up (via pad/joystick). Allows scroll delay and button overriding + //!\return true if selection should be moved up, false otherwise + bool Up(); + //!Move menu selection down (via pad/joystick). Allows scroll delay and button overriding + //!\return true if selection should be moved down, false otherwise + bool Down(); + + u8 type; //!< trigger type (TRIGGER_SIMPLE, TRIGGER_HELD, TRIGGER_BUTTON_ONLY, TRIGGER_BUTTON_ONLY_IN_FOCUS) + s32 chan; //!< Trigger controller channel (0-3, -1 for all) + WPADData wpad; //!< Wii controller trigger data + PADData pad; //!< GameCube controller trigger data +}; + +extern GuiTrigger userInput[4]; + +//!Primary GUI class. Most other classes inherit from this class. +class GuiElement +{ + public: + //!Constructor + GuiElement(); + //!Destructor + ~GuiElement(); + //!Set the element's parent + //!\param e Pointer to parent element + void SetParent(GuiElement * e); + //!Gets the element's parent + //!\return Pointer to parent element + GuiElement * GetParent(); + //!Gets the current leftmost coordinate of the element + //!Considers horizontal alignment, x offset, width, and parent element's GetLeft() / GetWidth() values + //!\return left coordinate + int GetLeft(); + //!Gets the current topmost coordinate of the element + //!Considers vertical alignment, y offset, height, and parent element's GetTop() / GetHeight() values + //!\return top coordinate + int GetTop(); + //!Sets the minimum y offset of the element + //!\param y Y offset + void SetMinY(int y); + //!Gets the minimum y offset of the element + //!\return Minimum Y offset + int GetMinY(); + //!Sets the maximum y offset of the element + //!\param y Y offset + void SetMaxY(int y); + //!Gets the maximum y offset of the element + //!\return Maximum Y offset + int GetMaxY(); + //!Sets the minimum x offset of the element + //!\param x X offset + void SetMinX(int x); + //!Gets the minimum x offset of the element + //!\return Minimum X offset + int GetMinX(); + //!Sets the maximum x offset of the element + //!\param x X offset + void SetMaxX(int x); + //!Gets the maximum x offset of the element + //!\return Maximum X offset + int GetMaxX(); + //!Gets the current width of the element. Does not currently consider the scale + //!\return width + int GetWidth(); + //!Gets the height of the element. Does not currently consider the scale + //!\return height + int GetHeight(); + //!Sets the size (width/height) of the element + //!\param w Width of element + //!\param h Height of element + void SetSize(int w, int h); + //!Checks whether or not the element is visible + //!\return true if visible, false otherwise + bool IsVisible(); + //!Checks whether or not the element is selectable + //!\return true if selectable, false otherwise + bool IsSelectable(); + //!Checks whether or not the element is clickable + //!\return true if clickable, false otherwise + bool IsClickable(); + //!Checks whether or not the element is holdable + //!\return true if holdable, false otherwise + bool IsHoldable(); + //!Sets whether or not the element is selectable + //!\param s Selectable + void SetSelectable(bool s); + //!Sets whether or not the element is clickable + //!\param c Clickable + void SetClickable(bool c); + //!Sets whether or not the element is holdable + //!\param c Holdable + void SetHoldable(bool d); + //!Gets the element's current state + //!\return state + int GetState(); + //!Gets the controller channel that last changed the element's state + //!\return Channel number (0-3, -1 = no channel) + int GetStateChan(); + //!Sets the element's alpha value + //!\param a alpha value + void SetAlpha(int a); + //!Gets the element's alpha value + //!Considers alpha, alphaDyn, and the parent element's GetAlpha() value + //!\return alpha + int GetAlpha(); + //!Gets the element's AngleDyn value + //!\return alpha + float GetAngleDyn(); + //!Sets the element's scale + //!\param s scale (1 is 100%) + void SetScale(float s); + //!Gets the element's current scale + //!Considers scale, scaleDyn, and the parent element's GetScale() value + virtual float GetScale(); + //!Set a new GuiTrigger for the element + //!\param t Pointer to GuiTrigger + void SetTrigger(GuiTrigger * t); + //!\overload + //!\param i Index of trigger array to set + //!\param t Pointer to GuiTrigger + void SetTrigger(u8 i, GuiTrigger * t); + //!Remove GuiTrigger for the element + //!\param i Index of trigger array to set + void RemoveTrigger(u8 i); + //!Checks whether rumble was requested by the element + //!\return true is rumble was requested, false otherwise + bool Rumble(); + //!Sets whether or not the element is requesting a rumble event + //!\param r true if requesting rumble, false if not + void SetRumble(bool r); + //!Set an effect for the element + //!\param e Effect to enable + //!\param a Amount of the effect (usage varies on effect) + //!\param t Target amount of the effect (usage varies on effect) + void SetEffect(int e, int a, int t=0); + //!This SetEffect is for EFFECT_GOROUND only + //!\param e Effect to enable + //!\param speed is for Circlespeed + //!\param circles Circleamount in degree ike 180 for 1/2 circle or 720 for 2 circles + //!\param r Circle Radius in pixel + //!\param startdegree Degree where to start circling + //!\param anglespeedset Set the speed of Angle rotating make 1 for same speed as Circlespeed //! or 0.5 for half the speed of the circlingspeed. Turn Anglecircling off by 0 to this param. //!\param center_x x co-ordinate of the center of circle. - //!\param center_y y co-ordinate of the center of circle. - void SetEffect(int e, int speed, f32 circles, int r, f32 startdegree, f32 anglespeedset, int center_x, int center_y); + //!\param center_y y co-ordinate of the center of circle. + void SetEffect(int e, int speed, f32 circles, int r, f32 startdegree, f32 anglespeedset, int center_x, int center_y); //!Gets the frequency from the above effect - //!\return element frequency - float GetFrequency(); - //!Sets an effect to be enabled on wiimote cursor over - //!\param e Effect to enable - //!\param a Amount of the effect (usage varies on effect) - //!\param t Target amount of the effect (usage varies on effect) - void SetEffectOnOver(int e, int a, int t=0); - //!Shortcut to SetEffectOnOver(EFFECT_SCALE, 4, 110) - void SetEffectGrow(); - //!Stops the current element effect - void StopEffect(); - //!Gets the current element effects - //!\return element effects + //!\return element frequency + float GetFrequency(); + //!Sets an effect to be enabled on wiimote cursor over + //!\param e Effect to enable + //!\param a Amount of the effect (usage varies on effect) + //!\param t Target amount of the effect (usage varies on effect) + void SetEffectOnOver(int e, int a, int t=0); + //!Shortcut to SetEffectOnOver(EFFECT_SCALE, 4, 110) + void SetEffectGrow(); + //!Stops the current element effect + void StopEffect(); + //!Gets the current element effects + //!\return element effects int GetEffect(); - //!Gets the current element on over effects + //!Gets the current element on over effects //!\return element on over effects - int GetEffectOnOver(); - //!Checks whether the specified coordinates are within the element's boundaries - //!\param x X coordinate - //!\param y Y coordinate - //!\return true if contained within, false otherwise - bool IsInside(int x, int y); - //!Sets the element's position - //!\param x X coordinate - //!\param y Y coordinate - void SetPosition(int x, int y, int z = 0); - //!Updates the element's effects (dynamic values) - //!Called by Draw(), used for animation purposes - void UpdateEffects(); - //!Sets a function to called after after Update() - //!Callback function can be used to response to changes in the state of the element, and/or update the element's attributes - void SetUpdateCallback(UpdateCallback u); - //!Checks whether the element is in focus - //!\return true if element is in focus, false otherwise - int IsFocused(); - //!Sets the element's visibility - //!\param v Visibility (true = visible) - virtual void SetVisible(bool v); - //!Sets the element's focus - //!\param f Focus (true = in focus) - virtual void SetFocus(int f); - //!Sets the element's state - //!\param s State (STATE_DEFAULT, STATE_SELECTED, STATE_CLICKED, STATE_DISABLED) - //!\param c Controller channel (0-3, -1 = none) - virtual void SetState(int s, int c = -1); - //!Resets the element's state to STATE_DEFAULT - virtual void ResetState(); - //!Gets whether or not the element is in STATE_SELECTED - //!\return true if selected, false otherwise - virtual int GetSelected(); - //!Sets the element's alignment respective to its parent element - //!\param hor Horizontal alignment (ALIGN_LEFT, ALIGN_RIGHT, ALIGN_CENTRE) - //!\param vert Vertical alignment (ALIGN_TOP, ALIGN_BOTTOM, ALIGN_MIDDLE) - virtual void SetAlignment(int hor, int vert); - //!Called constantly to allow the element to respond to the current input data - //!\param t Pointer to a GuiTrigger, containing the current input data from PAD/WPAD - virtual void Update(GuiTrigger * t); - //!Called constantly to redraw the element - virtual void Draw(); - virtual void DrawTooltip(); - protected: - void Lock(); - void Unlock(); - static mutex_t mutex; - friend class SimpleLock; - - //int position2; //! B Scrollbariable - bool visible; //!< Visibility of the element. If false, Draw() is skipped - int focus; //!< Element focus (-1 = focus disabled, 0 = not focused, 1 = focused) - int dontsetfocus; //! _elements; //!< Contains all elements within the GuiWindow -}; - -//!Converts image data into GX-useable RGBA8. Currently designed for use only with PNG files -class GuiImageData -{ - public: - //!Constructor - //!Converts the image data to RGBA8 - expects PNG format - //!\param i Image data - GuiImageData(const u8 * i); - GuiImageData(const char * imgPath, const u8 * buffer); - GuiImageData(const u8 * img, int imgSize); - GuiImageData(const char *path, const char *file, const u8 * buffer, bool force_widescreen=false, const u8 * wbuffer=NULL); - //!Destructor - ~GuiImageData(); - //!Gets a pointer to the image data - //!\return pointer to image data - u8 * GetImage(); - //!Gets the image width - //!\return image width - int GetWidth(); - //!Gets the image height - //!\return image height - int GetHeight(); - //!LoadJpeg file - void LoadJpeg(const u8 *img, int imgSize); - //!RawTo4x4RGBA - void RawTo4x4RGBA(const unsigned char *src, void *dst, const unsigned int width, const unsigned int height); - //!Sets the image to grayscale - void SetGrayscale(void); - protected: - u8 * data; //!< Image data - int height; //!< Height of image - int width; //!< Width of image -}; - -//!Display, manage, and manipulate images in the GUI -class GuiImage : public GuiElement -{ - public: - //!Constructor - GuiImage(); - //!\overload - //!\param img Pointer to GuiImageData element - GuiImage(GuiImageData * img); - //!\overload - //!Sets up a new image from the image data specified - //!\param img - //!\param w Image width - //!\param h Image height - GuiImage(u8 * img, int w, int h); - //!\overload - //!Creates an image filled with the specified color - //!\param w Image width - //!\param h Image height - //!\param c Image color - GuiImage(int w, int h, GXColor c); - //! Copy Constructor - GuiImage(GuiImage &srcimage); - GuiImage(GuiImage *srcimage); - //! = operator for copying images - GuiImage &operator=(GuiImage &srcimage); - //!Destructor - ~GuiImage(); - //!Sets the image rotation angle for drawing - //!\param a Angle (in degrees) - void SetAngle(float a); - //!Gets the image rotation angle for drawing - float GetAngle(); - //!Sets the number of times to draw the image horizontally - //!\param t Number of times to draw the image - void SetTile(int t); - // true set horizontal scale to 0.8 //added - void SetWidescreen(bool w); - //!Constantly called to draw the image - void Draw(); - //!Gets the image data - //!\return pointer to image data - u8 * GetImage(); - //!Sets up a new image using the GuiImageData object specified - //!\param img Pointer to GuiImageData object - void SetImage(GuiImageData * img); - //!\overload - //!\param img Pointer to image data - //!\param w Width - //!\param h Height - void SetImage(u8 * img, int w, int h); - //!Gets the pixel color at the specified coordinates of the image - //!\param x X coordinate - //!\param y Y coordinate - GXColor GetPixel(int x, int y); - //!Sets the pixel color at the specified coordinates of the image - //!\param x X coordinate - //!\param y Y coordinate - //!\param color Pixel color - void SetPixel(int x, int y, GXColor color); - //!Sets the image to grayscale - void SetGrayscale(void); - //!Set/disable the use of parentelement angle (default true) - void SetParentAngle(bool a); - //!Directly modifies the image data to create a color-striped effect - //!Alters the RGB values by the specified amount - //!\param s Amount to increment/decrement the RGB values in the image - void ColorStripe(int s); - //!Sets a stripe effect on the image, overlaying alpha blended rectangles - //!Does not alter the image data - //!\param s Alpha amount to draw over the image - void SetStripe(int s); - s32 z; - void SetSkew(int XX1, int YY1,int XX2, int YY2,int XX3, int YY3,int XX4, int YY4); - void SetSkew(int *skew /* int skew[8] */ ); - int xx1; - int yy1; - int xx2; - int yy2; - int xx3; - int yy3; - int xx4; - int yy4; - int rxx1; - int ryy1; - int rxx2; - int ryy2; - int rxx3; - int ryy3; - int rxx4; - int ryy4; - protected: - int imgType; //!< Type of image data (IMAGE_TEXTURE, IMAGE_COLOR, IMAGE_DATA) - u8 * image; //!< Poiner to image data. May be shared with GuiImageData data - f32 imageangle; //!< Angle to draw the image - int tile; //!< Number of times to draw (tile) the image horizontally - int stripe; //!< Alpha value (0-255) to apply a stripe effect to the texture - short widescreen; //added - bool parentangle; -}; - -//!Display, manage, and manipulate text in the GUI -class GuiText : public GuiElement -{ - public: - //!Constructor - //!\param t Text - //!\param s Font size - //!\param c Font color - GuiText(const char * t, int s, GXColor c); - //!\overload - //!\Assumes SetPresets() has been called to setup preferred text attributes - //!\param t Text - GuiText(const char * t); - //!Destructor - ~GuiText(); - //!Sets the text of the GuiText element - //!\param t Text - void SetText(const char * t); - void SetTextf(const char *format, ...) __attribute__((format(printf,2,3))); - void SetText(const wchar_t * t); - //!Sets up preset values to be used by GuiText(t) - //!Useful when printing multiple text elements, all with the same attributes set - //!\param sz Font size - //!\param c Font color - //!\param w Maximum width of texture image (for text wrapping) - //!\param wrap Wrapmode when w>0 - //!\param s Font style - //!\param h Text alignment (horizontal) - //!\param v Text alignment (vertical) - static void SetPresets(int sz, GXColor c, int w, int wrap, u16 s, int h, int v); - //!Sets the font size - //!\param s Font size - void SetFontSize(int s); - //!Sets the maximum width of the drawn texture image - //!If the text exceeds this, it is wrapped to the next line - //!\param w Maximum width - //!\param m WrapMode - enum { - WRAP, - DOTTED, - SCROLL, - MARQUEE - }; - void SetMaxWidth(int w, short m=GuiText::WRAP); - //!Sets the font color - //!\param c Font color - void SetColor(GXColor c); - //!Sets the FreeTypeGX style attributes - //!\param s Style attributes - //!\param m Style-Mask attributes - void SetStyle(u16 s, u16 m=0xffff); - //!Sets the text alignment - //!\param hor Horizontal alignment (ALIGN_LEFT, ALIGN_RIGHT, ALIGN_CENTRE) - //!\param vert Vertical alignment (ALIGN_TOP, ALIGN_BOTTOM, ALIGN_MIDDLE) - void SetAlignment(int hor, int vert); - //!Sets the font - //!\param f Font - void SetFont(FreeTypeGX *f); - //!Get the Horizontal Size of Text - int GetTextWidth(); - // not NULL set horizontal scale to 0.75 //added - void SetWidescreen(bool w); - void SetNumLines(int n);//! these two are used to set the first line and numLine - void SetFirstLine(int n); - int GetNumLines();//! these return the line variables for this text - int GetFirstLine(); - int GetLineHeight(int n);//! returns the height of the #n of lines including spacing if wrap mode is on - int GetTotalLines(); - //!Constantly called to draw the text - void Draw(); - protected: - wchar_t* text; //!< Unicode text value - int size; //!< Font size - int maxWidth; //!< Maximum width of the generated text object (for text wrapping) - short wrapMode; - short scrollPos1; - short scrollPos2; - short scrollOffset; - u32 scrollDelay; - u16 style; //!< FreeTypeGX style attributes - GXColor color; //!< Font color - FreeTypeGX *font; - short widescreen; //added - //!these are default until the text is drawn - int firstLine; //!these are the first line and the number of lines drawn when the text is wrapped - int numLines;//! default is -1 and it means that all lines are drawn - int totalLines; //!this is the total # of lines when in wrap mode -}; - -//!Display, manage, and manipulate tooltips in the GUI. -class GuiTooltip : public GuiElement -{ - public: - //!Constructor - //!\param t Text - GuiTooltip(const char *t, int Alpha=255); - - //!Destructor - ~ GuiTooltip(); - - //!Gets the element's current scale - //!Considers scale, scaleDyn, and the parent element's GetScale() value - float GetScale(); - //!Sets the text of the GuiTooltip element - //!\param t Text - void SetText(const char * t); - void SetWidescreen(bool w); // timely a dummy - //!Constantly called to draw the GuiButton - void Draw(); - - protected: - GuiImage leftImage; //!< Tooltip left-image - GuiImage tileImage; //!< Tooltip tile-image - GuiImage rightImage; //!< Tooltip right-image - GuiText *text; -}; - - -//!Display, manage, and manipulate buttons in the GUI. Buttons can have images, icons, text, and sound set (all of which are optional) -class GuiButton : public GuiElement -{ - public: - //!Constructor - //!\param w Width - //!\param h Height - GuiButton(int w, int h); - //!\param img is the button GuiImage. it uses the height & width of this image for the button - //!\param imgOver is the button's over GuiImage - //!\param hor is horizontal alingment of the button - //!\param vert is verticle alignment of the button - //!\param x is xposition of the button - //!\param y is yposition of the button - //!\param trig is a GuiTrigger to assign to this button - //!\param sndOver is a GuiSound used for soundOnOver for this button - //!\param sndClick is a GuiSound used for clickSound of this button - //!\param grow sets effect grow for this button. 1 for yes ;0 for no - GuiButton(GuiImage* img, GuiImage* imgOver, int hor, int vert, int x, int y, GuiTrigger* trig, GuiSound* sndOver, GuiSound* sndClick, u8 grow); - //!\param same as all the parameters for the above button plus the following - //!\param tt is a GuiTooltip assigned to this button - //!\param ttx and tty are the xPOS and yPOS for this tooltip in relationship to the button - //!\param h_align and v_align are horizontal and verticle alignment for the tooltip in relationship to the button - GuiButton(GuiImage* img, GuiImage* imgOver, int hor, int vert, int x, int y, GuiTrigger* trig, GuiSound* sndOver, GuiSound* sndClick, u8 grow, GuiTooltip* tt, int ttx, int tty, int h_align, int v_align); - //!Destructor - ~GuiButton(); - //!Sets the button's image - //!\param i Pointer to GuiImage object - void SetImage(GuiImage* i); - //!Sets the button's image on over - //!\param i Pointer to GuiImage object - void SetImageOver(GuiImage* i); - //!Sets the button's image on hold - //!\param i Pointer to GuiImage object - void SetAngle(float a); - void SetImageHold(GuiImage* i); - //!Sets the button's image on click - //!\param i Pointer to GuiImage object - void SetImageClick(GuiImage* i); - //!Sets the button's icon - //!\param i Pointer to GuiImage object - void SetIcon(GuiImage* i); - //!Sets the button's icon on over - //!\param i Pointer to GuiImage object - void SetIconOver(GuiImage* i); - //!Sets the button's icon on hold - //!\param i Pointer to GuiImage object - void SetIconHold(GuiImage* i); - //!Sets the button's icon on click - //!\param i Pointer to GuiImage object - void SetIconClick(GuiImage* i); - //!Sets the button's label - //!\param t Pointer to GuiText object - //!\param n Index of label to set (optional, default is 0) - void SetLabel(GuiText* t, int n = 0); - //!Sets the button's label on over (eg: different colored text) - //!\param t Pointer to GuiText object - //!\param n Index of label to set (optional, default is 0) - void SetLabelOver(GuiText* t, int n = 0); - //!Sets the button's label on hold - //!\param t Pointer to GuiText object - //!\param n Index of label to set (optional, default is 0) - void SetLabelHold(GuiText* t, int n = 0); - //!Sets the button's label on click - //!\param t Pointer to GuiText object - //!\param n Index of label to set (optional, default is 0) - void SetLabelClick(GuiText* t, int n = 0); - //!Sets the sound to play on over - //!\param s Pointer to GuiSound object - void SetSoundOver(GuiSound * s); - //!Sets the sound to play on hold - //!\param s Pointer to GuiSound object - void SetSoundHold(GuiSound * s); - //!Sets the sound to play on click - //!\param s Pointer to GuiSound object - void SetSoundClick(GuiSound * s); - //!\param reset the soundover to NULL - void RemoveSoundOver(); - //!\param reset the soundclick to NULL - void RemoveSoundClick(); - //!Constantly called to draw the GuiButtons ToolTip - //!Sets the button's Tooltip on over - //!\param tt Pointer to GuiElement object, x & y Positioning, h & v Align - void SetToolTip(GuiTooltip* tt, int x, int y, int h=ALIGN_RIGHT, int v=ALIGN_TOP); - - void RemoveToolTip(); - //!Constantly called to draw the GuiButton - void Draw(); - void DrawTooltip(); - //!Constantly called to allow the GuiButton to respond to updated input data - //!\param t Pointer to a GuiTrigger, containing the current input data from PAD/WPAD - void Update(GuiTrigger * t); - //!Deactivate/Activate pointing on Games while B scrolling - void ScrollIsOn(int f); - void SetSkew(int XX1, int YY1,int XX2, int YY2,int XX3, int YY3,int XX4, int YY4); - void SetSkew(int *skew /* int skew[8] */ ); - protected: - GuiImage * image; //!< Button image (default) - GuiImage * imageOver; //!< Button image for STATE_SELECTED - GuiImage * imageHold; //!< Button image for STATE_HELD - GuiImage * imageClick; //!< Button image for STATE_CLICKED - GuiImage * icon; //!< Button icon (drawn after button image) - GuiImage * iconOver; //!< Button icon for STATE_SELECTED - GuiImage * iconHold; //!< Button icon for STATE_HELD - GuiImage * iconClick; //!< Button icon for STATE_CLICKED - GuiTooltip *toolTip; - time_t time1, time2;//!< Tooltip timeconstants - GuiText * label[3]; //!< Label(s) to display (default) - GuiText * labelOver[3]; //!< Label(s) to display for STATE_SELECTED - GuiText * labelHold[3]; //!< Label(s) to display for STATE_HELD - GuiText * labelClick[3]; //!< Label(s) to display for STATE_CLICKED - GuiSound * soundOver; //!< Sound to play for STATE_SELECTED - GuiSound * soundHold; //!< Sound to play for STATE_HELD - GuiSound * soundClick; //!< Sound to play for STATE_CLICKED -}; - -typedef struct _keytype { - char ch, chShift, chalt, chalt2; -} Key; - -//!On-screen keyboard -class GuiKeyboard : public GuiWindow -{ - public: - GuiKeyboard(char * t, u32 m, int min, int lang); - ~GuiKeyboard(); - void Update(GuiTrigger * t); - char kbtextstr[256]; - protected: - u32 kbtextmaxlen; - Key keys[4][11]; - int shift; - int caps; - int alt; - int alt2; - GuiText * kbText; - GuiImage * keyTextboxImg; - GuiText * keyCapsText; - GuiImage * keyCapsImg; - GuiImage * keyCapsOverImg; - GuiButton * keyCaps; - GuiText * keyAltText; - GuiImage * keyAltImg; - GuiImage * keyAltOverImg; - GuiButton * keyAlt; - GuiText * keyAlt2Text; - GuiImage * keyAlt2Img; - GuiImage * keyAlt2OverImg; - GuiButton * keyAlt2; - GuiText * keyShiftText; - GuiImage * keyShiftImg; - GuiImage * keyShiftOverImg; - GuiButton * keyShift; - GuiText * keyBackText; - GuiImage * keyBackImg; - GuiImage * keyBackOverImg; - GuiButton * keyBack; - GuiText * keyClearText; - GuiImage * keyClearImg; - GuiImage * keyClearOverImg; - GuiButton * keyClear; - GuiImage * keySpaceImg; - GuiImage * keySpaceOverImg; - GuiButton * keySpace; - GuiButton * keyBtn[4][11]; - GuiImage * keyImg[4][11]; - GuiImage * keyImgOver[4][11]; - GuiText * keyTxt[4][11]; - GuiImageData * keyTextbox; - GuiImageData * key; - GuiImageData * keyOver; - GuiImageData * keyMedium; - GuiImageData * keyMediumOver; - GuiImageData * keyLarge; - GuiImageData * keyLargeOver; - GuiSound * keySoundOver; - GuiSound * keySoundClick; - GuiTrigger * trigA; - GuiTrigger * trigB; -}; - -typedef struct _optionlist { - int length; - char name[MAX_OPTIONS][60]; - char value[MAX_OPTIONS][30]; -} OptionList; - -//!Display a list of menu options -class GuiOptionBrowser : public GuiElement -{ - public: - GuiOptionBrowser(int w, int h, OptionList * l, const u8 *imagebg, int scrollbar); - GuiOptionBrowser(int w, int h, OptionList * l, const char * themePath, const u8 *imagebg, int scrollbar, int start); - ~GuiOptionBrowser(); - void SetCol2Position(int x); - int FindMenuItem(int c, int d); - int GetClickedOption(); - int GetSelectedOption(); - void ResetState(); - void SetFocus(int f); - void Draw(); - void TriggerUpdate(); - void Update(GuiTrigger * t); - GuiText * optionVal[PAGESIZE]; - protected: - int selectedItem; - int listOffset; - bool listChanged; - OptionList * options; - int optionIndex[PAGESIZE]; - GuiButton * optionBtn[PAGESIZE]; - GuiText * optionTxt[PAGESIZE]; - GuiImage * optionBg[PAGESIZE]; - - GuiButton * arrowUpBtn; - GuiButton * arrowDownBtn; - GuiButton * scrollbarBoxBtn; - - GuiImage * bgOptionsImg; - GuiImage * bgOptionsOverImg; - GuiImage * scrollbarImg; - GuiImage * arrowDownImg; - GuiImage * arrowDownOverImg; - GuiImage * arrowUpImg; - GuiImage * arrowUpOverImg; - GuiImage * scrollbarBoxImg; - GuiImage * scrollbarBoxOverImg; - - GuiImageData * bgOptions; - GuiImageData * bgOptionsOver; - GuiImageData * bgOptionsEntry; - GuiImageData * scrollbar; - GuiImageData * arrowDown; - GuiImageData * arrowDownOver; - GuiImageData * arrowUp; - GuiImageData * arrowUpOver; - GuiImageData * scrollbarBox; - GuiImageData * scrollbarBoxOver; - - GuiSound * btnSoundOver; - GuiSound * btnSoundClick; + f32 yoffsetDynFloat; //!< Integer sucks float is need by some parts + int changervar; //!< Changervariable for some stuff + int alpha; //!< Element alpha value (0-255) + f32 scale; //!< Element scale (1 = 100%) + f32 angleDyn; //!< AngleDyn for EFFECT_GOROUND + f32 anglespeed; //! _elements; //!< Contains all elements within the GuiWindow +}; + +//!Converts image data into GX-useable RGBA8. Currently designed for use only with PNG files +class GuiImageData +{ + public: + //!Constructor + //!Converts the image data to RGBA8 - expects PNG format + //!\param i Image data + GuiImageData(const u8 * i); + GuiImageData(const char * imgPath, const u8 * buffer); + GuiImageData(const u8 * img, int imgSize); + GuiImageData(const char *path, const char *file, const u8 * buffer, bool force_widescreen=false, const u8 * wbuffer=NULL); + //!Destructor + ~GuiImageData(); + //!Gets a pointer to the image data + //!\return pointer to image data + u8 * GetImage(); + //!Gets the image width + //!\return image width + int GetWidth(); + //!Gets the image height + //!\return image height + int GetHeight(); + //!LoadJpeg file + void LoadJpeg(const u8 *img, int imgSize); + //!RawTo4x4RGBA + void RawTo4x4RGBA(const unsigned char *src, void *dst, const unsigned int width, const unsigned int height); + //!Sets the image to grayscale + void SetGrayscale(void); + protected: + u8 * data; //!< Image data + int height; //!< Height of image + int width; //!< Width of image +}; + +//!Display, manage, and manipulate images in the GUI +class GuiImage : public GuiElement +{ + public: + //!Constructor + GuiImage(); + //!\overload + //!\param img Pointer to GuiImageData element + GuiImage(GuiImageData * img); + //!\overload + //!Sets up a new image from the image data specified + //!\param img + //!\param w Image width + //!\param h Image height + GuiImage(u8 * img, int w, int h); + //!\overload + //!Creates an image filled with the specified color + //!\param w Image width + //!\param h Image height + //!\param c Image color + GuiImage(int w, int h, GXColor c); + //! Copy Constructor + GuiImage(GuiImage &srcimage); + GuiImage(GuiImage *srcimage); + //! = operator for copying images + GuiImage &operator=(GuiImage &srcimage); + //!Destructor + ~GuiImage(); + //!Sets the image rotation angle for drawing + //!\param a Angle (in degrees) + void SetAngle(float a); + //!Gets the image rotation angle for drawing + float GetAngle(); + //!Sets the number of times to draw the image horizontally + //!\param t Number of times to draw the image + void SetTile(int t); + // true set horizontal scale to 0.8 //added + void SetWidescreen(bool w); + //!Constantly called to draw the image + void Draw(); + //!Gets the image data + //!\return pointer to image data + u8 * GetImage(); + //!Sets up a new image using the GuiImageData object specified + //!\param img Pointer to GuiImageData object + void SetImage(GuiImageData * img); + //!\overload + //!\param img Pointer to image data + //!\param w Width + //!\param h Height + void SetImage(u8 * img, int w, int h); + //!Gets the pixel color at the specified coordinates of the image + //!\param x X coordinate + //!\param y Y coordinate + GXColor GetPixel(int x, int y); + //!Sets the pixel color at the specified coordinates of the image + //!\param x X coordinate + //!\param y Y coordinate + //!\param color Pixel color + void SetPixel(int x, int y, GXColor color); + //!Sets the image to grayscale + void SetGrayscale(void); + //!Set/disable the use of parentelement angle (default true) + void SetParentAngle(bool a); + //!Directly modifies the image data to create a color-striped effect + //!Alters the RGB values by the specified amount + //!\param s Amount to increment/decrement the RGB values in the image + void ColorStripe(int s); + //!Sets a stripe effect on the image, overlaying alpha blended rectangles + //!Does not alter the image data + //!\param s Alpha amount to draw over the image + void SetStripe(int s); + s32 z; + void SetSkew(int XX1, int YY1,int XX2, int YY2,int XX3, int YY3,int XX4, int YY4); + void SetSkew(int *skew /* int skew[8] */ ); + int xx1; + int yy1; + int xx2; + int yy2; + int xx3; + int yy3; + int xx4; + int yy4; + int rxx1; + int ryy1; + int rxx2; + int ryy2; + int rxx3; + int ryy3; + int rxx4; + int ryy4; + protected: + int imgType; //!< Type of image data (IMAGE_TEXTURE, IMAGE_COLOR, IMAGE_DATA) + u8 * image; //!< Poiner to image data. May be shared with GuiImageData data + f32 imageangle; //!< Angle to draw the image + int tile; //!< Number of times to draw (tile) the image horizontally + int stripe; //!< Alpha value (0-255) to apply a stripe effect to the texture + short widescreen; //added + bool parentangle; +}; + +//!Display, manage, and manipulate text in the GUI +class GuiText : public GuiElement +{ + public: + //!Constructor + //!\param t Text + //!\param s Font size + //!\param c Font color + GuiText(const char * t, int s, GXColor c); + //!\overload + //!\Assumes SetPresets() has been called to setup preferred text attributes + //!\param t Text + GuiText(const char * t); + //!Destructor + ~GuiText(); + //!Sets the text of the GuiText element + //!\param t Text + void SetText(const char * t); + void SetTextf(const char *format, ...) __attribute__((format(printf,2,3))); + void SetText(const wchar_t * t); + //!Sets up preset values to be used by GuiText(t) + //!Useful when printing multiple text elements, all with the same attributes set + //!\param sz Font size + //!\param c Font color + //!\param w Maximum width of texture image (for text wrapping) + //!\param wrap Wrapmode when w>0 + //!\param s Font style + //!\param h Text alignment (horizontal) + //!\param v Text alignment (vertical) + static void SetPresets(int sz, GXColor c, int w, int wrap, u16 s, int h, int v); + //!Sets the font size + //!\param s Font size + void SetFontSize(int s); + //!Sets the maximum width of the drawn texture image + //!If the text exceeds this, it is wrapped to the next line + //!\param w Maximum width + //!\param m WrapMode + enum { + WRAP, + DOTTED, + SCROLL, + MARQUEE + }; + void SetMaxWidth(int w, short m=GuiText::WRAP); + //!Sets the font color + //!\param c Font color + void SetColor(GXColor c); + //!Sets the FreeTypeGX style attributes + //!\param s Style attributes + //!\param m Style-Mask attributes + void SetStyle(u16 s, u16 m=0xffff); + //!Sets the text alignment + //!\param hor Horizontal alignment (ALIGN_LEFT, ALIGN_RIGHT, ALIGN_CENTRE) + //!\param vert Vertical alignment (ALIGN_TOP, ALIGN_BOTTOM, ALIGN_MIDDLE) + void SetAlignment(int hor, int vert); + //!Sets the font + //!\param f Font + void SetFont(FreeTypeGX *f); + //!Get the Horizontal Size of Text + int GetTextWidth(); + // not NULL set horizontal scale to 0.75 //added + void SetWidescreen(bool w); + void SetNumLines(int n);//! these two are used to set the first line and numLine + void SetFirstLine(int n); + int GetNumLines();//! these return the line variables for this text + int GetFirstLine(); + int GetLineHeight(int n);//! returns the height of the #n of lines including spacing if wrap mode is on + int GetTotalLines(); + //!Constantly called to draw the text + void Draw(); + protected: + wchar_t* text; //!< Unicode text value + int size; //!< Font size + int maxWidth; //!< Maximum width of the generated text object (for text wrapping) + short wrapMode; + short scrollPos1; + short scrollPos2; + short scrollOffset; + u32 scrollDelay; + u16 style; //!< FreeTypeGX style attributes + GXColor color; //!< Font color + FreeTypeGX *font; + short widescreen; //added + //!these are default until the text is drawn + int firstLine; //!these are the first line and the number of lines drawn when the text is wrapped + int numLines;//! default is -1 and it means that all lines are drawn + int totalLines; //!this is the total # of lines when in wrap mode +}; + +//!Display, manage, and manipulate tooltips in the GUI. +class GuiTooltip : public GuiElement +{ + public: + //!Constructor + //!\param t Text + GuiTooltip(const char *t, int Alpha=255); + + //!Destructor + ~ GuiTooltip(); + + //!Gets the element's current scale + //!Considers scale, scaleDyn, and the parent element's GetScale() value + float GetScale(); + //!Sets the text of the GuiTooltip element + //!\param t Text + void SetText(const char * t); + void SetWidescreen(bool w); // timely a dummy + //!Constantly called to draw the GuiButton + void Draw(); + + protected: + GuiImage leftImage; //!< Tooltip left-image + GuiImage tileImage; //!< Tooltip tile-image + GuiImage rightImage; //!< Tooltip right-image + GuiText *text; +}; + + +//!Display, manage, and manipulate buttons in the GUI. Buttons can have images, icons, text, and sound set (all of which are optional) +class GuiButton : public GuiElement +{ + public: + //!Constructor + //!\param w Width + //!\param h Height + GuiButton(int w, int h); + //!\param img is the button GuiImage. it uses the height & width of this image for the button + //!\param imgOver is the button's over GuiImage + //!\param hor is horizontal alingment of the button + //!\param vert is verticle alignment of the button + //!\param x is xposition of the button + //!\param y is yposition of the button + //!\param trig is a GuiTrigger to assign to this button + //!\param sndOver is a GuiSound used for soundOnOver for this button + //!\param sndClick is a GuiSound used for clickSound of this button + //!\param grow sets effect grow for this button. 1 for yes ;0 for no + GuiButton(GuiImage* img, GuiImage* imgOver, int hor, int vert, int x, int y, GuiTrigger* trig, GuiSound* sndOver, GuiSound* sndClick, u8 grow); + //!\param same as all the parameters for the above button plus the following + //!\param tt is a GuiTooltip assigned to this button + //!\param ttx and tty are the xPOS and yPOS for this tooltip in relationship to the button + //!\param h_align and v_align are horizontal and verticle alignment for the tooltip in relationship to the button + GuiButton(GuiImage* img, GuiImage* imgOver, int hor, int vert, int x, int y, GuiTrigger* trig, GuiSound* sndOver, GuiSound* sndClick, u8 grow, GuiTooltip* tt, int ttx, int tty, int h_align, int v_align); + //!Destructor + ~GuiButton(); + //!Sets the button's image + //!\param i Pointer to GuiImage object + void SetImage(GuiImage* i); + //!Sets the button's image on over + //!\param i Pointer to GuiImage object + void SetImageOver(GuiImage* i); + //!Sets the button's image on hold + //!\param i Pointer to GuiImage object + void SetAngle(float a); + void SetImageHold(GuiImage* i); + //!Sets the button's image on click + //!\param i Pointer to GuiImage object + void SetImageClick(GuiImage* i); + //!Sets the button's icon + //!\param i Pointer to GuiImage object + void SetIcon(GuiImage* i); + //!Sets the button's icon on over + //!\param i Pointer to GuiImage object + void SetIconOver(GuiImage* i); + //!Sets the button's icon on hold + //!\param i Pointer to GuiImage object + void SetIconHold(GuiImage* i); + //!Sets the button's icon on click + //!\param i Pointer to GuiImage object + void SetIconClick(GuiImage* i); + //!Sets the button's label + //!\param t Pointer to GuiText object + //!\param n Index of label to set (optional, default is 0) + void SetLabel(GuiText* t, int n = 0); + //!Sets the button's label on over (eg: different colored text) + //!\param t Pointer to GuiText object + //!\param n Index of label to set (optional, default is 0) + void SetLabelOver(GuiText* t, int n = 0); + //!Sets the button's label on hold + //!\param t Pointer to GuiText object + //!\param n Index of label to set (optional, default is 0) + void SetLabelHold(GuiText* t, int n = 0); + //!Sets the button's label on click + //!\param t Pointer to GuiText object + //!\param n Index of label to set (optional, default is 0) + void SetLabelClick(GuiText* t, int n = 0); + //!Sets the sound to play on over + //!\param s Pointer to GuiSound object + void SetSoundOver(GuiSound * s); + //!Sets the sound to play on hold + //!\param s Pointer to GuiSound object + void SetSoundHold(GuiSound * s); + //!Sets the sound to play on click + //!\param s Pointer to GuiSound object + void SetSoundClick(GuiSound * s); + //!\param reset the soundover to NULL + void RemoveSoundOver(); + //!\param reset the soundclick to NULL + void RemoveSoundClick(); + //!Constantly called to draw the GuiButtons ToolTip + //!Sets the button's Tooltip on over + //!\param tt Pointer to GuiElement object, x & y Positioning, h & v Align + void SetToolTip(GuiTooltip* tt, int x, int y, int h=ALIGN_RIGHT, int v=ALIGN_TOP); + + void RemoveToolTip(); + //!Constantly called to draw the GuiButton + void Draw(); + void DrawTooltip(); + //!Constantly called to allow the GuiButton to respond to updated input data + //!\param t Pointer to a GuiTrigger, containing the current input data from PAD/WPAD + void Update(GuiTrigger * t); + //!Deactivate/Activate pointing on Games while B scrolling + void ScrollIsOn(int f); + void SetSkew(int XX1, int YY1,int XX2, int YY2,int XX3, int YY3,int XX4, int YY4); + void SetSkew(int *skew /* int skew[8] */ ); + protected: + GuiImage * image; //!< Button image (default) + GuiImage * imageOver; //!< Button image for STATE_SELECTED + GuiImage * imageHold; //!< Button image for STATE_HELD + GuiImage * imageClick; //!< Button image for STATE_CLICKED + GuiImage * icon; //!< Button icon (drawn after button image) + GuiImage * iconOver; //!< Button icon for STATE_SELECTED + GuiImage * iconHold; //!< Button icon for STATE_HELD + GuiImage * iconClick; //!< Button icon for STATE_CLICKED + GuiTooltip *toolTip; + time_t time1, time2;//!< Tooltip timeconstants + GuiText * label[3]; //!< Label(s) to display (default) + GuiText * labelOver[3]; //!< Label(s) to display for STATE_SELECTED + GuiText * labelHold[3]; //!< Label(s) to display for STATE_HELD + GuiText * labelClick[3]; //!< Label(s) to display for STATE_CLICKED + GuiSound * soundOver; //!< Sound to play for STATE_SELECTED + GuiSound * soundHold; //!< Sound to play for STATE_HELD + GuiSound * soundClick; //!< Sound to play for STATE_CLICKED +}; + +typedef struct _keytype { + char ch, chShift, chalt, chalt2; +} Key; + +//!On-screen keyboard +class GuiKeyboard : public GuiWindow +{ + public: + GuiKeyboard(char * t, u32 m, int min, int lang); + ~GuiKeyboard(); + void Update(GuiTrigger * t); + char kbtextstr[256]; + protected: + u32 kbtextmaxlen; + Key keys[4][11]; + int shift; + int caps; + int alt; + int alt2; + GuiText * kbText; + GuiImage * keyTextboxImg; + GuiText * keyCapsText; + GuiImage * keyCapsImg; + GuiImage * keyCapsOverImg; + GuiButton * keyCaps; + GuiText * keyAltText; + GuiImage * keyAltImg; + GuiImage * keyAltOverImg; + GuiButton * keyAlt; + GuiText * keyAlt2Text; + GuiImage * keyAlt2Img; + GuiImage * keyAlt2OverImg; + GuiButton * keyAlt2; + GuiText * keyShiftText; + GuiImage * keyShiftImg; + GuiImage * keyShiftOverImg; + GuiButton * keyShift; + GuiText * keyBackText; + GuiImage * keyBackImg; + GuiImage * keyBackOverImg; + GuiButton * keyBack; + GuiText * keyClearText; + GuiImage * keyClearImg; + GuiImage * keyClearOverImg; + GuiButton * keyClear; + GuiImage * keySpaceImg; + GuiImage * keySpaceOverImg; + GuiButton * keySpace; + GuiButton * keyBtn[4][11]; + GuiImage * keyImg[4][11]; + GuiImage * keyImgOver[4][11]; + GuiText * keyTxt[4][11]; + GuiImageData * keyTextbox; + GuiImageData * key; + GuiImageData * keyOver; + GuiImageData * keyMedium; + GuiImageData * keyMediumOver; + GuiImageData * keyLarge; + GuiImageData * keyLargeOver; + GuiSound * keySoundOver; + GuiSound * keySoundClick; GuiTrigger * trigA; - GuiTrigger * trigB; - GuiTrigger * trigHeldA; -}; - -//!Display a list of files -class GuiFileBrowser : public GuiElement -{ - public: - GuiFileBrowser(int w, int h); - ~GuiFileBrowser(); - void DisableTriggerUpdate(bool set); - void ResetState(); - void SetFocus(int f); - void Draw(); - void TriggerUpdate(); - void Update(GuiTrigger * t); - GuiButton * fileList[PAGESIZE]; - protected: - int selectedItem; - bool listChanged; - bool triggerdisabled; - - GuiText * fileListText[PAGESIZE]; - GuiText * fileListTextOver[PAGESIZE]; - GuiImage * fileListBg[PAGESIZE]; - //GuiImage * fileListArchives[PAGESIZE]; - //GuiImage * fileListDefault[PAGESIZE]; - GuiImage * fileListFolder[PAGESIZE]; - //GuiImage * fileListGFX[PAGESIZE]; - //GuiImage * fileListPLS[PAGESIZE]; - //GuiImage * fileListSFX[PAGESIZE]; - //GuiImage * fileListTXT[PAGESIZE]; - //GuiImage * fileListXML[PAGESIZE]; - - GuiButton * arrowUpBtn; - GuiButton * arrowDownBtn; - GuiButton * scrollbarBoxBtn; - - GuiImage * bgFileSelectionImg; - GuiImage * scrollbarImg; - GuiImage * arrowDownImg; - GuiImage * arrowUpImg; - GuiImage * scrollbarBoxImg; - - GuiImageData * bgFileSelection; - GuiImageData * bgFileSelectionEntry; - //GuiImageData * fileArchives; - //GuiImageData * fileDefault; - GuiImageData * fileFolder; - //GuiImageData * fileGFX; - //GuiImageData * filePLS; - //GuiImageData * fileSFX; - //GuiImageData * fileTXT; - //GuiImageData * fileXML; - GuiImageData * scrollbar; - GuiImageData * arrowDown; - GuiImageData * arrowUp; - GuiImageData * scrollbarBox; - - GuiSound * btnSoundOver; - GuiSound * btnSoundClick; - GuiTrigger * trigA; - GuiTrigger * trigHeldA; -}; - -#endif + GuiTrigger * trigB; +}; + +typedef struct _optionlist { + int length; + char name[MAX_OPTIONS][60]; + char value[MAX_OPTIONS][30]; +} OptionList; + +//!Display a list of menu options +class GuiOptionBrowser : public GuiElement +{ + public: + GuiOptionBrowser(int w, int h, OptionList * l, const u8 *imagebg, int scrollbar); + GuiOptionBrowser(int w, int h, OptionList * l, const char * themePath, const u8 *imagebg, int scrollbar, int start); + ~GuiOptionBrowser(); + void SetCol2Position(int x); + int FindMenuItem(int c, int d); + int GetClickedOption(); + int GetSelectedOption(); + void ResetState(); + void SetFocus(int f); + void Draw(); + void TriggerUpdate(); + void Update(GuiTrigger * t); + GuiText * optionVal[PAGESIZE]; + protected: + int selectedItem; + int listOffset; + bool listChanged; + OptionList * options; + int optionIndex[PAGESIZE]; + GuiButton * optionBtn[PAGESIZE]; + GuiText * optionTxt[PAGESIZE]; + GuiImage * optionBg[PAGESIZE]; + + GuiButton * arrowUpBtn; + GuiButton * arrowDownBtn; + GuiButton * scrollbarBoxBtn; + + GuiImage * bgOptionsImg; + GuiImage * bgOptionsOverImg; + GuiImage * scrollbarImg; + GuiImage * arrowDownImg; + GuiImage * arrowDownOverImg; + GuiImage * arrowUpImg; + GuiImage * arrowUpOverImg; + GuiImage * scrollbarBoxImg; + GuiImage * scrollbarBoxOverImg; + + GuiImageData * bgOptions; + GuiImageData * bgOptionsOver; + GuiImageData * bgOptionsEntry; + GuiImageData * scrollbar; + GuiImageData * arrowDown; + GuiImageData * arrowDownOver; + GuiImageData * arrowUp; + GuiImageData * arrowUpOver; + GuiImageData * scrollbarBox; + GuiImageData * scrollbarBoxOver; + + GuiSound * btnSoundOver; + GuiSound * btnSoundClick; + GuiTrigger * trigA; + GuiTrigger * trigB; + GuiTrigger * trigHeldA; +}; + +//!Display a list of files +class GuiFileBrowser : public GuiElement +{ + public: + GuiFileBrowser(int w, int h); + ~GuiFileBrowser(); + void DisableTriggerUpdate(bool set); + void ResetState(); + void SetFocus(int f); + void Draw(); + void TriggerUpdate(); + void Update(GuiTrigger * t); + GuiButton * fileList[PAGESIZE]; + protected: + int selectedItem; + bool listChanged; + bool triggerdisabled; + + GuiText * fileListText[PAGESIZE]; + GuiText * fileListTextOver[PAGESIZE]; + GuiImage * fileListBg[PAGESIZE]; + //GuiImage * fileListArchives[PAGESIZE]; + //GuiImage * fileListDefault[PAGESIZE]; + GuiImage * fileListFolder[PAGESIZE]; + //GuiImage * fileListGFX[PAGESIZE]; + //GuiImage * fileListPLS[PAGESIZE]; + //GuiImage * fileListSFX[PAGESIZE]; + //GuiImage * fileListTXT[PAGESIZE]; + //GuiImage * fileListXML[PAGESIZE]; + + GuiButton * arrowUpBtn; + GuiButton * arrowDownBtn; + GuiButton * scrollbarBoxBtn; + + GuiImage * bgFileSelectionImg; + GuiImage * scrollbarImg; + GuiImage * arrowDownImg; + GuiImage * arrowUpImg; + GuiImage * scrollbarBoxImg; + + GuiImageData * bgFileSelection; + GuiImageData * bgFileSelectionEntry; + //GuiImageData * fileArchives; + //GuiImageData * fileDefault; + GuiImageData * fileFolder; + //GuiImageData * fileGFX; + //GuiImageData * filePLS; + //GuiImageData * fileSFX; + //GuiImageData * fileTXT; + //GuiImageData * fileXML; + GuiImageData * scrollbar; + GuiImageData * arrowDown; + GuiImageData * arrowUp; + GuiImageData * scrollbarBox; + + GuiSound * btnSoundOver; + GuiSound * btnSoundClick; + GuiTrigger * trigA; + GuiTrigger * trigHeldA; +}; + +#endif diff --git a/source/libwiigui/gui_customoptionbrowser.cpp b/source/libwiigui/gui_customoptionbrowser.cpp index 070ac65f..5d9f0111 100644 --- a/source/libwiigui/gui_customoptionbrowser.cpp +++ b/source/libwiigui/gui_customoptionbrowser.cpp @@ -157,7 +157,7 @@ GuiCustomOptionBrowser::GuiCustomOptionBrowser(int w, int h, customOptionList * trigA->SetSimpleTrigger(-1, WPAD_BUTTON_A | WPAD_CLASSIC_BUTTON_A, PAD_BUTTON_A); trigHeldA = new GuiTrigger; trigHeldA->SetHeldTrigger(-1, WPAD_BUTTON_A, PAD_BUTTON_A); - btnSoundClick = new GuiSound(button_click_pcm, button_click_pcm_size, SOUND_PCM, Settings.sfxvolume); + btnSoundClick = new GuiSound(button_click_pcm, button_click_pcm_size, Settings.sfxvolume); snprintf(imgPath, sizeof(imgPath), "%s%s", themePath, custombg); bgOptions = new GuiImageData(imgPath, imagebg); diff --git a/source/libwiigui/gui_element.cpp b/source/libwiigui/gui_element.cpp index 80f2eb49..abffffb1 100644 --- a/source/libwiigui/gui_element.cpp +++ b/source/libwiigui/gui_element.cpp @@ -770,3 +770,82 @@ SimpleLock::~SimpleLock() { element->Unlock(); } +#if 0 + + +GuiElement + + +protected: + void Lock(); + void Unlock(); + friend class SimpleLock; +private: +// static mutex_t mutex; + static mutex_t _lock_mutex; + lwp_t _lock_thread; + u16 _lock_count; + lwpq_t _lock_queue; + u16 _lock_queue_count; + + + + + +void GuiElement::Lock() +{ + LWP_MutexLock(_lock_mutex); + + if(_lock_thread = LWP_GetSelf()) // i am self + { + _lock_count++; // inc count of locks; + LWP_MutexUnlock(_lock_mutex); + return; + } + + if(_lock_thread == THREAD_NULL) // element is not locked + { + _lock_thread = LWP_GetSelf(); + _lock_count = 1; + LWP_MutexUnlock(_lock_mutex); + return; + } + + // element is locked + if(_lock_queue == LWP_TQUEUE_NULL) // no queue + { + LWP_InitQueue(&_lock_queue); // init queue + _lock_queue_count = 0; // clear count of threads in queue; + } + _lock_queue_count++; // inc count of threads in queue; + LWP_MutexUnlock(_lock_mutex); // unlock + LWP_ThreadSleep(_lock_queue); // and sleep + LWP_MutexLock(_lock_mutex); // waked up , will lock + if(--_lock_queue_count == 0) // dec count of threads in queue; + { + // is the last thread in queue + LWP_CloseQueue(_lock_queue); // close the queue + _lock_queue = LWP_TQUEUE_NULL; + lock(); // try lock again; + } + LWP_MutexUnlock(_lock_mutex) + return; +} +void GuiElement::Unlock() +{ + LWP_MutexLock(_lock_mutex); + // only the thread was locked this element, can call unlock + if(_lock_thread == LWP_GetSelf()) // but we check it here – safe is safe + { + if(--_lock_queue_count == 0) // dec count of locks; + { + _lock_thread = THREAD_NULL; // is the last thread in queue + if(_lock_queue != LWP_TQUEUE_NULL) // has a queue + LWP_ThreadSignal(_lock_queue); // wake the next thread in queue + } + } + LWP_MutexUnlock(_lock_mutex) +} + + +#endif \ No newline at end of file diff --git a/source/libwiigui/gui_filebrowser.cpp b/source/libwiigui/gui_filebrowser.cpp index 2561efbc..389c8ee0 100644 --- a/source/libwiigui/gui_filebrowser.cpp +++ b/source/libwiigui/gui_filebrowser.cpp @@ -10,7 +10,7 @@ #include "gui.h" #include "prompts/filebrowser.h" -#include "../settings/cfg.h" +#include "settings/cfg.h" /** * Constructor for the GuiFileBrowser class. @@ -31,8 +31,8 @@ GuiFileBrowser::GuiFileBrowser(int w, int h) trigHeldA = new GuiTrigger; trigHeldA->SetHeldTrigger(-1, WPAD_BUTTON_A | WPAD_CLASSIC_BUTTON_A, PAD_BUTTON_A); - btnSoundOver = new GuiSound(button_over_pcm, button_over_pcm_size, SOUND_PCM); - btnSoundClick = new GuiSound(button_click_pcm, button_click_pcm_size, SOUND_PCM); + btnSoundOver = new GuiSound(button_over_pcm, button_over_pcm_size, Settings.sfxvolume); + btnSoundClick = new GuiSound(button_click_pcm, button_click_pcm_size, Settings.sfxvolume); char imgPath[100]; snprintf(imgPath, sizeof(imgPath), "%sbg_browser.png", CFG.theme_path); diff --git a/source/libwiigui/gui_gamebrowser.cpp b/source/libwiigui/gui_gamebrowser.cpp index 2f083331..36d4d1e3 100644 --- a/source/libwiigui/gui_gamebrowser.cpp +++ b/source/libwiigui/gui_gamebrowser.cpp @@ -40,7 +40,7 @@ GuiGameBrowser::GuiGameBrowser(int w, int h, struct discHdr * l, int gameCnt, co trigA->SetSimpleTrigger(-1, WPAD_BUTTON_A | WPAD_CLASSIC_BUTTON_A, PAD_BUTTON_A); trigHeldA = new GuiTrigger; trigHeldA->SetHeldTrigger(-1, WPAD_BUTTON_A, PAD_BUTTON_A); - btnSoundClick = new GuiSound(button_click_pcm, button_click_pcm_size, SOUND_PCM, Settings.sfxvolume); + btnSoundClick = new GuiSound(button_click_pcm, button_click_pcm_size, Settings.sfxvolume); snprintf(imgPath, sizeof(imgPath), "%sbg_options.png", themePath); bgGames = new GuiImageData(imgPath, imagebg); diff --git a/source/libwiigui/gui_gamecarousel.cpp b/source/libwiigui/gui_gamecarousel.cpp index bf90d99a..37451248 100644 --- a/source/libwiigui/gui_gamecarousel.cpp +++ b/source/libwiigui/gui_gamecarousel.cpp @@ -69,8 +69,8 @@ noCover(nocover_png) trigMinus = new GuiTrigger; trigMinus->SetButtonOnlyTrigger(-1, WPAD_BUTTON_MINUS | WPAD_CLASSIC_BUTTON_MINUS, 0); - btnSoundClick = new GuiSound(button_click2_pcm, button_click2_pcm_size, SOUND_PCM, Settings.sfxvolume); - btnSoundOver = new GuiSound(button_over_pcm, button_over_pcm_size, SOUND_PCM, Settings.sfxvolume); + btnSoundClick = new GuiSound(button_click2_pcm, button_click2_pcm_size, Settings.sfxvolume); + btnSoundOver = new GuiSound(button_over_pcm, button_over_pcm_size, Settings.sfxvolume); snprintf(imgPath, sizeof(imgPath), "%sstartgame_arrow_left.png", CFG.theme_path); imgLeft = new GuiImageData(imgPath, startgame_arrow_left_png); diff --git a/source/libwiigui/gui_gamegrid.cpp b/source/libwiigui/gui_gamegrid.cpp index ae7c3c63..30acbcd2 100644 --- a/source/libwiigui/gui_gamegrid.cpp +++ b/source/libwiigui/gui_gamegrid.cpp @@ -317,8 +317,8 @@ noCover(nocoverFlat_png) trigMinus = new GuiTrigger; trigMinus->SetButtonOnlyTrigger(-1, WPAD_BUTTON_MINUS | WPAD_CLASSIC_BUTTON_MINUS, 0); - btnSoundClick = new GuiSound(button_click2_pcm, button_click2_pcm_size, SOUND_PCM, Settings.sfxvolume); - btnSoundOver = new GuiSound(button_over_pcm, button_over_pcm_size, SOUND_PCM, Settings.sfxvolume); + btnSoundClick = new GuiSound(button_click2_pcm, button_click2_pcm_size, Settings.sfxvolume); + btnSoundOver = new GuiSound(button_over_pcm, button_over_pcm_size, Settings.sfxvolume); int btnHeight = (int) lround(sqrt(RADIUS*RADIUS - 90000)-RADIUS-50); diff --git a/source/libwiigui/gui_keyboard.cpp b/source/libwiigui/gui_keyboard.cpp index e36eaac3..dbd01b94 100644 --- a/source/libwiigui/gui_keyboard.cpp +++ b/source/libwiigui/gui_keyboard.cpp @@ -343,8 +343,8 @@ GuiKeyboard::GuiKeyboard(char * t, u32 max, int min, int lang) keyLarge = new GuiImageData(keyboard_largekey_over_png); keyLargeOver = new GuiImageData(keyboard_largekey_over_png); - keySoundOver = new GuiSound(button_over_pcm, button_over_pcm_size, SOUND_PCM, Settings.sfxvolume); - keySoundClick = new GuiSound(button_click_pcm, button_click_pcm_size, SOUND_PCM, Settings.sfxvolume); + keySoundOver = new GuiSound(button_over_pcm, button_over_pcm_size, Settings.sfxvolume); + keySoundClick = new GuiSound(button_click_pcm, button_click_pcm_size, Settings.sfxvolume); trigA = new GuiTrigger; trigA->SetSimpleTrigger(-1, WPAD_BUTTON_A | WPAD_CLASSIC_BUTTON_A, PAD_BUTTON_A); trigB = new GuiTrigger; diff --git a/source/libwiigui/gui_optionbrowser.cpp b/source/libwiigui/gui_optionbrowser.cpp index 05f196a4..acf6b2ba 100644 --- a/source/libwiigui/gui_optionbrowser.cpp +++ b/source/libwiigui/gui_optionbrowser.cpp @@ -10,6 +10,7 @@ #include "gui.h" #include "../wpad.h" +#include "Settings/cfg.h" #include @@ -37,7 +38,7 @@ GuiOptionBrowser::GuiOptionBrowser(int w, int h, OptionList * l, const u8 *image trigHeldA = new GuiTrigger; trigHeldA->SetHeldTrigger(-1, WPAD_BUTTON_A, PAD_BUTTON_A); - btnSoundClick = new GuiSound(button_click_pcm, button_click_pcm_size, SOUND_PCM); + btnSoundClick = new GuiSound(button_click_pcm, button_click_pcm_size, Settings.sfxvolume); bgOptions = new GuiImageData(imagebg); bgOptionsImg = new GuiImage(bgOptions); @@ -149,7 +150,7 @@ GuiOptionBrowser::GuiOptionBrowser(int w, int h, OptionList * l, const char *the trigA->SetSimpleTrigger(-1, WPAD_BUTTON_A | WPAD_CLASSIC_BUTTON_A, PAD_BUTTON_A); trigHeldA = new GuiTrigger; trigHeldA->SetHeldTrigger(-1, WPAD_BUTTON_A, PAD_BUTTON_A); - btnSoundClick = new GuiSound(button_click_pcm, button_click_pcm_size, SOUND_PCM); + btnSoundClick = new GuiSound(button_click_pcm, button_click_pcm_size, Settings.sfxvolume); snprintf(imgPath, sizeof(imgPath), "%sbg_options.png", themePath); bgOptions = new GuiImageData(imgPath, imagebg); diff --git a/source/libwiigui/gui_searchbar.cpp b/source/libwiigui/gui_searchbar.cpp index 0ffa5f36..97683d15 100644 --- a/source/libwiigui/gui_searchbar.cpp +++ b/source/libwiigui/gui_searchbar.cpp @@ -39,8 +39,8 @@ text(NULL, 22, (GXColor) {0, 0, 0, 255}), buttons(0), keyImageData(keyboard_key_png), keyOverImageData(keyboard_key_over_png), -sndOver(button_over_pcm, button_over_pcm_size, SOUND_PCM, Settings.sfxvolume), -sndClick(button_click_pcm, button_click_pcm_size, SOUND_PCM, Settings.sfxvolume) +sndOver(button_over_pcm, button_over_pcm_size, Settings.sfxvolume), +sndClick(button_click_pcm, button_click_pcm_size, Settings.sfxvolume) { char imgPath[100]; trig.SetSimpleTrigger(-1, WPAD_BUTTON_A | WPAD_CLASSIC_BUTTON_A, PAD_BUTTON_A); diff --git a/source/libwiigui/gui_sound.cpp b/source/libwiigui/gui_sound.cpp index a08c2ef9..e565296a 100644 --- a/source/libwiigui/gui_sound.cpp +++ b/source/libwiigui/gui_sound.cpp @@ -5,32 +5,277 @@ * * gui_sound.cpp * + * decoder modification by ardi 2009 + * * GUI class definitions ***************************************************************************/ #include "gui.h" +#include +#include "gecko.h" +#include "gui_sound_decoder.h" + + +#define BUFFER_SIZE 8192 + + +/*************************************************************** + * + * D E C O D E R – L I S T + * + * + ***************************************************************/ + +GuiSoundDecoder::DecoderListEntry *GuiSoundDecoder::DecoderList = NULL; +GuiSoundDecoder::DecoderListEntry &GuiSoundDecoder::RegisterDecoder(DecoderListEntry &Decoder, GuiSoundDecoderCreate fnc) +{ + if(Decoder.fnc != fnc) + { + Decoder.fnc = fnc; + Decoder.next = DecoderList; + DecoderList = &Decoder; + } + return Decoder; +} +GuiSoundDecoder *GuiSoundDecoder::GetDecoder(const u8 * snd, u32 len, bool snd_is_allocated) +{ + for(DecoderListEntry *de = DecoderList; de; de=de->next) + { + GuiSoundDecoder *d = NULL; + try{ d = de->fnc(snd, len, snd_is_allocated); } + catch(const char *error){ + gprintf("%s", error); } + catch(...){} + if(d) return d; + } + return NULL; +} + + +/*************************************************************** + * + * D E C O D E R – T H R E A D + * + * + ***************************************************************/ + +static GuiSound *GuiSoundPlayer[16] = {NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL}; + +static lwp_t GuiSoundDecoderThreadHandle = LWP_THREAD_NULL; +static bool GuiSoundDecoderThreadRunning = false; +static bool GuiSoundDecoderDataRquested = false; + +void *GuiSoundDecoderThread(void *args) +{ + GuiSoundDecoderThreadRunning = true; + do + { + if(GuiSoundDecoderDataRquested) + { + GuiSoundDecoderDataRquested = false; + GuiSound **players = GuiSoundPlayer; + for( int i = 0; i < 16; ++i , ++players) + { + GuiSound *player = *players; + if(player) + player->DecoderCallback(); + } + } + if(!GuiSoundDecoderDataRquested) + usleep(50); + } while(GuiSoundDecoderThreadRunning); + return 0; +} + +/*************************************************************** + * + * A S N D – C A L L B A C K + * + * + ***************************************************************/ + +void GuiSoundPlayerCallback(s32 Voice) +{ + if(Voice >= 0 && Voice < 16 && GuiSoundPlayer[Voice]) + { + GuiSoundPlayer[Voice]->PlayerCallback(); + GuiSoundDecoderDataRquested = true; + } +} + +/*************************************************************** + * + * R A W - D E C O D E R + * Decoder for Raw-PCM-Datas (16bit Stereo 48kHz) + * + ***************************************************************/ +class GuiSoundDecoderRAW : public GuiSoundDecoder +{ +protected: + GuiSoundDecoderRAW(const u8 * snd, u32 len, bool snd_is_allocated) + { + pcm_start = snd; + is_allocated = snd_is_allocated; + pcm_end = pcm_start+len; + pos = pcm_start; + is_running = false; + + } +public: + ~GuiSoundDecoderRAW() + { + while(is_running) usleep(50); + if(is_allocated) delete [] pcm_start; + } + static GuiSoundDecoder *Create(const u8 * snd, u32 len, bool snd_is_allocated) + { + try { return new GuiSoundDecoderRAW(snd, len, snd_is_allocated); } + catch(...) {} + return NULL; + } + s32 GetFormat() + { + return VOICE_STEREO_16BIT; + } + s32 GetSampleRate() + { + return 48000; + } + /* Read reads data from stream to buffer + return: >0 = readed bytes; + 0 = EOF; + <0 = Error; + */ + int Read(u8 * buffer, int buffer_size) + { + if(pos >= pcm_end) + return 0; // EOF + + is_running = true; + if(pos + buffer_size > pcm_end) + buffer_size = pcm_end-pos; + memcpy(buffer, pos, buffer_size); + pos += buffer_size; + is_running = false; + return buffer_size; + } + int Rewind() + { + pos = pcm_start; + return 0; + } +private: + const u8 *pcm_start; + const u8 *pcm_end; + bool is_allocated; + const u8 *pos; + bool is_running; + +}; + +/*************************************************************** + * + * G u i S o u n d + * + * + ***************************************************************/ +#define GuiSoundBufferReady 0x01 +#define GuiSoundBufferEOF 0x02 +#define GuiSoundFinish 0x04 +static int GuiSoundCount = 0; /** * Constructor for the GuiSound class. */ -GuiSound::GuiSound(const u8 * snd, s32 len, int t) +GuiSound::GuiSound(const u8 *s, int l, int v/*=100*/, bool r/*=true*/, bool a/*=false*/) { - sound = snd; - length = len; - type = t; + if(GuiSoundCount++ == 0 || GuiSoundDecoderThreadHandle == LWP_THREAD_NULL) + { + LWP_CreateThread(&GuiSoundDecoderThreadHandle,GuiSoundDecoderThread,NULL,NULL,32*1024,80); + } voice = -1; - volume = 100; - loop = false; + play_buffer[0] = (u8*)memalign(32, BUFFER_SIZE*3); // tripple-buffer first is played + play_buffer[1] = play_buffer[0] + BUFFER_SIZE; // second is waiting + play_buffer[2] = play_buffer[1] + BUFFER_SIZE; // third is decoding + buffer_nr = 0; // current playbuffer + buffer_pos = 0; // current idx to write in buffer + buffer_ready = false; + buffer_eof = false; + loop = false; // play looped + volume = v; // volume + decoder = NULL; + if(play_buffer[0]) // playbuffer ok + Load(s, l, r, a); } - -GuiSound::GuiSound(const u8 * snd, s32 len, int t, int v) +bool GuiSound::Load(const u8 *s, int l, bool r/*=false*/, bool a/*=false*/) { - sound = snd; - length = len; - type = t; + Stop(); + if(!play_buffer[0]) return false; + GuiSoundDecoder *newDecoder = GuiSoundDecoder::GetDecoder(s, l, a); + if(!newDecoder && r) newDecoder = GuiSoundDecoderRAW::Create(s, l, a); + if(newDecoder) + { + delete decoder; + decoder = newDecoder; + return true; + } + else if(a) + delete [] s; + return false; +} +GuiSound::GuiSound(const char *p, int v/*=100*/) +{ + if(GuiSoundCount++ == 0 || GuiSoundDecoderThreadHandle == LWP_THREAD_NULL) + { + LWP_CreateThread(&GuiSoundDecoderThreadHandle,GuiSoundDecoderThread,NULL,NULL,32*1024,80); + } voice = -1; - volume = v; - loop = false; + play_buffer[0] = (u8*)memalign(32, BUFFER_SIZE*3); // tripple-buffer first is played + play_buffer[1] = play_buffer[0] + BUFFER_SIZE; // second is waiting + play_buffer[2] = play_buffer[1] + BUFFER_SIZE; // third is decoding + buffer_nr = 0; // current playbuffer + buffer_pos = 0; // current idx to write in buffer + buffer_ready = false; + buffer_eof = false; + loop = false; // play looped + volume = v; // volume + decoder = NULL; + if(play_buffer[0]) // playbuffer ok + Load(p); +} +bool GuiSound::Load(const char *p) +{ + Stop(); // stop playing + if(!play_buffer[0]) return false; + + bool ret = false; + voice = -2; // -2 marks loading from file + u32 filesize = 0; + u8 *buffer = NULL; + size_t result; + + FILE * pFile = fopen (p, "rb"); + if(pFile) + { + // get file size: + fseek (pFile , 0 , SEEK_END); + filesize = ftell (pFile); + fseek (pFile , 0 , SEEK_SET); + + // allocate memory to contain the whole file: + buffer = new(std::nothrow) u8[filesize]; + if (buffer) + { + // copy the file into the buffer: + result = fread (buffer, 1, filesize, pFile); + if (result == filesize) + ret= Load(buffer, filesize, false, true); + else + delete [] buffer; + } + fclose (pFile); + } + return ret; } /** @@ -38,145 +283,89 @@ GuiSound::GuiSound(const u8 * snd, s32 len, int t, int v) */ GuiSound::~GuiSound() { - if(type == SOUND_OGG) - StopOgg(); -} - -int GuiSound::PlayOggFile(char * path) -{ /* - u32 filesize = 0; - char * bufferogg = NULL; - size_t resultogg; - - FILE * pFile; - pFile = fopen (path, "rb"); - - // get file size: - fseek (pFile , 0 , SEEK_END); - filesize = ftell (pFile); - rewind (pFile); - - // allocate memory to contain the whole file: - bufferogg = (char*) malloc (sizeof(char)*filesize); - if (bufferogg == NULL) {fputs (" Memory error",stderr); exit (2);} - - // copy the file into the buffer: - resultogg = fread (bufferogg,1,filesize,pFile); - if (resultogg != filesize) {fputs (" Reading error",stderr); exit (3);} - - fclose (pFile); - - sound = (const u8 *) bufferogg; - length = filesize; - */ - int ret = PlayOggFromFile(path, loop); - SetVolumeOgg(255*(volume/100.0)); - return ret; + if(!loop) while(voice >= 0) usleep(50); + Stop(); + if(--GuiSoundCount == 0 && GuiSoundDecoderThreadHandle != LWP_THREAD_NULL) + { + GuiSoundDecoderThreadRunning = false; + LWP_JoinThread(GuiSoundDecoderThreadHandle,NULL); + GuiSoundDecoderThreadHandle = LWP_THREAD_NULL; + } + delete decoder; + free(play_buffer[0]); } void GuiSound::Play() { - int vol; - - switch(type) + Stop(); // stop playing if it played + if(!play_buffer[0]) return; + if(!decoder) return; // no decoder or no play_buffer -> no playing + // initialize the buffer + buffer_nr = 0; // allways starts with buffer 0 + buffer_pos = 0; // reset position + buffer_ready = false; + buffer_eof = false; + decoder->Rewind(); // play from begin + DecoderCallback(); // fill first buffer; + if(!buffer_ready || buffer_eof) // if first buffer not ready -> no play + return; + voice = ASND_GetFirstUnusedVoice(); + if(voice >= 0) { - case SOUND_PCM: - vol = 255*(volume/100.0); - voice = ASND_GetFirstUnusedVoice(); - if(voice >= 0) - ASND_SetVoice(voice, VOICE_STEREO_16BIT, 48000, 0, - (u8 *)sound, length, vol, vol, NULL); - break; - - case SOUND_OGG: - voice = 0; - if(loop) - PlayOgg(mem_open((char *)sound, length), 0, OGG_INFINITE_TIME); - else - PlayOgg(mem_open((char *)sound, length), 0, OGG_ONE_TIME); - SetVolumeOgg(255*(volume/100.0)); - break; + s32 vol = (255*volume)/100; + s32 format = decoder->GetFormat(); + s32 samplerate = decoder->GetSampleRate(); + s32 first_pos = buffer_pos; + // switch to next buffer + buffer_nr = 1; + buffer_pos = 0; + buffer_ready = false; + buffer_eof = false; + DecoderCallback(); // fill second buffer; + GuiSoundPlayer[voice] = this; // activate Callbacks for this voice + // Play the voice + ASND_SetVoice(voice, format, samplerate, 0, play_buffer[0], first_pos, vol, vol, GuiSoundPlayerCallback); } } - +/* +int GuiSound::PlayOggFile(char * path) +{ + if(Load(path)) + Play(); + return 1; +} +*/ void GuiSound::Stop() { - if(voice < 0) - return; - - switch(type) - { - case SOUND_PCM: - ASND_StopVoice(voice); - break; - - case SOUND_OGG: - StopOgg(); - break; - } + if(voice < 0) return ; + GuiSoundPlayer[voice] = NULL; // disable Callbacks + SND_StopVoice(voice); + voice = -1; } void GuiSound::Pause() { - if(voice < 0) - return; - - switch(type) - { - case SOUND_PCM: - ASND_PauseVoice(voice, 1); - break; - - case SOUND_OGG: - PauseOgg(1); - break; - } + if(voice < 0) return ; + ASND_PauseVoice(voice, 1); } void GuiSound::Resume() { - if(voice < 0) - return; - - switch(type) - { - case SOUND_PCM: - ASND_PauseVoice(voice, 0); - break; - - case SOUND_OGG: - PauseOgg(0); - break; - } + if(voice < 0) return ; + ASND_PauseVoice(voice, 0); } bool GuiSound::IsPlaying() { - if(ASND_StatusVoice(voice) == SND_WORKING || ASND_StatusVoice(voice) == SND_WAITING) - return true; - else - return false; + return voice >= 0; } void GuiSound::SetVolume(int vol) { volume = vol; - - if(voice < 0) - return; - + if(voice < 0) return ; int newvol = 255*(volume/100.0); - - switch(type) - { - case SOUND_PCM: - ASND_ChangeVolumeVoice(voice, newvol, newvol); - break; - - case SOUND_OGG: - SetVolumeOgg(255*(volume/100.0)); - break; - } + ASND_ChangeVolumeVoice(voice, newvol, newvol); } void GuiSound::SetLoop(bool l) @@ -184,12 +373,68 @@ void GuiSound::SetLoop(bool l) loop = l; } -s32 GuiSound::GetPlayTime() +void GuiSound::DecoderCallback() { - return GetTimeOgg(); + if(buffer_ready || buffer_eof) // if buffer ready or EOF -> nothing + return; + bool error=false; + while(buffer_pos < BUFFER_SIZE) + { + int ret = decoder->Read(&play_buffer[buffer_nr][buffer_pos], BUFFER_SIZE-buffer_pos); + if(ret > 0) + buffer_pos += ret; // ok -> fill the buffer more + else if(ret == 0) // EOF from decoder + { + if(loop) + decoder->Rewind(); // if loop -> rewind and fill the buffer more + else if(buffer_pos) + break; // has data in buffer -> play the buffer + else + buffer_eof = true; // no data in buffer -> return EOF + return; + } + else if(ret < 0) // an ERROR + { + if(buffer_pos) + break; // has data in buffer -> play the buffer + else if(loop) + { + if(!error) // if no prev error + { + decoder->Rewind(); // if loop -> rewind + error = true; // set error-state + continue; // and fill the buffer more + } + buffer_eof = true; // has prev error -> error in first block -> return EOF + return; + } + else + { + buffer_eof = true; // no loop -> return EOF + return; + } + } + error = false; // clear error-state + } + buffer_ready = true; +} +void GuiSound::PlayerCallback() +{ + if(buffer_eof) // if EOF + { + if(ASND_TestPointer(voice, play_buffer[(buffer_nr+2)%3])==0) // test prev. Buffer + Stop(); + } + else if(buffer_ready) // if buffer ready + { + if(ASND_AddVoice(voice, play_buffer[buffer_nr], buffer_pos)==SND_OK) // add buffer + { + // next buffer + buffer_nr = (buffer_nr+1)%3; + buffer_pos = 0; + buffer_ready= false; + buffer_eof = false; + } + } } -void GuiSound::SetPlayTime(s32 time_pos) -{ - SetTimeOgg(time_pos); -} diff --git a/source/libwiigui/gui_sound_decoder.h b/source/libwiigui/gui_sound_decoder.h new file mode 100644 index 00000000..dd62bea3 --- /dev/null +++ b/source/libwiigui/gui_sound_decoder.h @@ -0,0 +1,111 @@ +/**************************************************************************** + * libwiigui + * + * Tantric 2009 + * + * gui_sound_decoder.h + * + * by ardi 2009 + * + * GUI class definitions + ***************************************************************************/ + +#ifndef GUI_SOUND_DECODER_H +#define GUI_SOUND_DECODER_H + +#include + +#define REGISTER_GUI_SOUND_DECODER(decoder) GuiSoundDecoder::DecoderListEntry decoder##_l = GuiSoundDecoder::RegisterDecoder(decoder##_l, decoder::Create) +class GuiSoundDecoder; +typedef GuiSoundDecoder *(*GuiSoundDecoderCreate)(const u8 * snd, u32 len, bool snd_is_allocated); + +class GuiSoundDecoder +{ +protected: + GuiSoundDecoder(){}; // Constructors must protected so it can create only with Init(...); +public: + virtual ~GuiSoundDecoder(){}; + // begin API + // --------- + // each Decoder must have an own static Create(...) fnc + // static GuiSoundDecoder *Create(const u8 * snd, u32 len, bool snd_is_allocated); + virtual s32 GetFormat()=0; + virtual s32 GetSampleRate()=0; + /* Read reads data from stream to buffer + return: >0 = readed bytes; + 0 = EOF; + <0 = Error; + */ + virtual int Read(u8 * buffer, int buffer_size)=0; + // set the stream to the start + virtual int Rewind()=0; + // ------- + // end API + + + struct DecoderListEntry + { + GuiSoundDecoderCreate fnc; + DecoderListEntry *next; + }; + static DecoderListEntry &RegisterDecoder(DecoderListEntry &Decoder, GuiSoundDecoderCreate fnc); + static GuiSoundDecoder *GetDecoder(const u8 * snd, u32 len, bool snd_is_allocated); +private: + static DecoderListEntry *DecoderList; + GuiSoundDecoder(GuiSoundDecoder&); // no copy +}; + +#define BIG_ENDIAN_HOST 1 // Wii PPC is a Big-Endian-Host + +#if BIG_ENDIAN_HOST + +inline uint16_t be16(const uint8_t *p8) +{ + return *((uint16_t*)p8); +} +inline uint32_t be32(const uint8_t *p8) +{ + return *((uint32_t*)p8); +} +inline uint16_t le16(const uint8_t *p8) +{ + uint16_t ret = p8[1]<<8 | p8[0]; + return ret; +} +inline uint32_t le32(const uint8_t *p8) +{ + uint32_t ret = p8[3]<<24 | p8[2]<<16 | p8[1]<<8 | p8[0]; + return ret; +} + +#elif LITTLE_ENDIAN_HOST +inline uint16_t be16(const uint8_t *p8) +{ + uint16_t ret = p8[0]<<8 | p8[1]; + return ret; +} +inline uint32_t be32(const uint8_t *p8) +{ + uint32_t ret = p8[0]<<24 | p8[1]<<16 | p8[2]<<8 | p8[3]; + return ret; +} +inline uint16_t le16(const uint8_t *p8) +{ + return *((uint16_t*)p8); +} +inline uint32_t le32(const uint8_t *p8) +{ + return *((uint32_t*)p8); +} +#else + #error "BIG_ENDIAN_HOST or LITTLE_ENDIAN_HOST not setted" +#endif /* XXX_ENDIAN_HOST */ + +#define be16inc(p8) (p8+=2, be16(p8-2)) +#define le16inc(p8) (p8+=2, le16(p8-2)) +#define be32inc(p8) (p8+=4, be32(p8-4)) +#define le32inc(p8) (p8+=4, le32(p8-4)) + + + +#endif /* GUI_SOUND_DECODER_H */ diff --git a/source/libwiigui/gui_sound_decoder_aiff.cpp b/source/libwiigui/gui_sound_decoder_aiff.cpp new file mode 100644 index 00000000..b3201511 --- /dev/null +++ b/source/libwiigui/gui_sound_decoder_aiff.cpp @@ -0,0 +1,165 @@ +/**************************************************************************** + * libwiigui + * + * ardi 2009 + * + * gui_sound_plugin_aif.cpp + * + * GUI class definitions + ***************************************************************************/ + +#include +#include +#include +#include +#include + +#include "gui_sound_decoder.h" + +// ------ +// Copyright (C) 1988-1991 Apple Computer, Inc. +#ifndef HUGE_VAL +# define HUGE_VAL HUGE +#endif + +# define UnsignedToFloat(u) (((double)((long)(u - 2147483647L - 1))) + 2147483648.0) + +static double ConvertFromIeeeExtended(const u8* bytes) +{ + double f; + int expon; + u32 hiMant, loMant; + + expon = ((bytes[0] & 0x7F) << 8) | (bytes[1] & 0xFF); + hiMant = ((unsigned long)(bytes[2] & 0xFF) << 24) + | ((unsigned long)(bytes[3] & 0xFF) << 16) + | ((unsigned long)(bytes[4] & 0xFF) << 8) + | ((unsigned long)(bytes[5] & 0xFF)); + loMant = ((unsigned long)(bytes[6] & 0xFF) << 24) + | ((unsigned long)(bytes[7] & 0xFF) << 16) + | ((unsigned long)(bytes[8] & 0xFF) << 8) + | ((unsigned long)(bytes[9] & 0xFF)); + + if (expon == 0 && hiMant == 0 && loMant == 0) + f = 0; + else + { + if (expon == 0x7FFF) + f = HUGE_VAL; + else + { + expon -= 16383; + f = ldexp(UnsignedToFloat(hiMant), expon-=31); + f += ldexp(UnsignedToFloat(loMant), expon-=32); + } + } + + if (bytes[0] & 0x80) + return -f; + else + return f; +} +// ------ + +class GuiSoundDecoderAIFF : public GuiSoundDecoder +{ +protected: + GuiSoundDecoderAIFF(const u8 * snd, u32 len, bool snd_is_allocated) + { + sound = snd; + length =len; + is_allocated = snd_is_allocated; + is_running = false; + + const u8 *in_ptr = sound; + + if(be32inc(in_ptr) != 0x464F524D /*'FORM'*/) throw("No FORM chunk"); + if(be32inc(in_ptr)+8 != len) throw("wrong Size"); + if(be32inc(in_ptr) != 0x41494646 /*'AIFF'*/) throw("No AIFF chunk"); + + while(in_ptr+8 < sound+len) + { + u32 chunk_id = be32inc(in_ptr); + u32 chunk_size = be32inc(in_ptr); + const u8 *chunk_start = in_ptr; + switch(chunk_id) + { + case 0x434F4D4D /*'COMM'*/: + channelCount = be16inc(in_ptr); + in_ptr += 4; // skip numSampleFrames + bytePerSample = (be16inc(in_ptr)+7)/8; + if(bytePerSample < 1 && bytePerSample > 2) throw("wrong bits per Sample"); + sampleRate = ConvertFromIeeeExtended(in_ptr); + break; + case 0x53534E44 /*'SSND'*/: + pcm_start = in_ptr + 8; + pcm_end = chunk_start+chunk_size; + break; + } + in_ptr = chunk_start+chunk_size; + } + currentPos = sound; + } +public: + ~GuiSoundDecoderAIFF() + { + while(is_running) usleep(50); + if(is_allocated) delete [] sound; + } + static GuiSoundDecoder *Create(const u8 * snd, u32 len, bool snd_is_allocated) + { + if(snd && len>12 && snd[0]=='F' && snd[1]=='O' && snd[2]=='R' && snd[3]=='M' + && snd[8]=='A' && snd[9]=='I' && snd[10]=='F' && snd[11]=='F') + return new GuiSoundDecoderAIFF(snd, len, snd_is_allocated); + return NULL; + } + s32 GetFormat() + { + if(bytePerSample == 2) + return channelCount==2 ? VOICE_STEREO_16BIT : VOICE_MONO_16BIT; + else + return channelCount==2 ? VOICE_STEREO_8BIT : VOICE_MONO_8BIT; + } + s32 GetSampleRate() + { + return sampleRate; + } + /* Read reads data from stream to buffer + return: >0 = readed bytes; + 0 = EOF; + <0 = Error; + */ + int Read(u8 * buffer, int buffer_size) + { + if(currentPos >= pcm_end) + return 0; // EOF + + is_running = true; + if(currentPos + buffer_size > pcm_end) + buffer_size = pcm_end-currentPos; + memcpy(buffer, currentPos, buffer_size); + currentPos += buffer_size; + is_running = false; + return buffer_size; + } + int Rewind() + { + while(is_running) usleep(50); + currentPos = pcm_start; + return 0; + } +private: + const u8 *sound; + u32 length; + bool is_allocated; + bool is_running; + + u32 sampleRate; + u16 channelCount; + u16 bytePerSample; + const u8 *pcm_start; + const u8 *pcm_end; + const u8 *currentPos; +}; + +REGISTER_GUI_SOUND_DECODER(GuiSoundDecoderAIFF); diff --git a/source/libwiigui/gui_sound_decoder_bns.cpp b/source/libwiigui/gui_sound_decoder_bns.cpp new file mode 100644 index 00000000..630f5fc9 --- /dev/null +++ b/source/libwiigui/gui_sound_decoder_bns.cpp @@ -0,0 +1,259 @@ +/**************************************************************************** + * libwiigui + * + * Tantric 2009 + * + * gui_sound_plugin_bns.cpp + * + * by ardi 2009 + * + * Decoder for Wii bns-sound + * + * GUI class definitions + ***************************************************************************/ + +#include +#include + +#include "gui_sound_decoder.h" +#define BIG_ENDIAN_HOST 1 + + + + +class chanel_t +{ +public: + void Reset() + { + currentPos = startPos; + hist1 = hist2 = 0; + } + int DecodeNextBlock() + { + int Offset = 0; + if(currentPos == loopStart) + { + loop_hist1 = hist1; + loop_hist2 = hist2; + } + if(loopStart > startPos && currentPos >= endPos) + { + currentPos = loopStart; + hist1 = loop_hist1; + hist2 = loop_hist2; + Offset = loopOffset; + + } + + if(currentPos+8 <= endPos) + { + u16 index = (*currentPos >> 4) & 0x07; + s32 scale = 1 << (*currentPos++ & 0x0F); + for(int i = 0; i < 14; i+=2) + { + nibbles[i] = ((s8)*currentPos) >> 4; + nibbles[i+1] = ((s8)((*currentPos++) << 4)) >> 4; + } + for(int i = 0; i < 14; ++i) + { + s32 sample = (scale * nibbles[i])<<11; + sample += coEfficients[index * 2] * hist1; + sample += coEfficients[index * 2 + 1] * hist2; + sample += 1024; + sample = sample >> 11; + if(sample > 32767) + sample = 32767; + else if(sample < -32768) + sample = -32768; + pcm[i] = sample; + + hist2 = hist1; + hist1 = sample; + } + return Offset; + } + return -1; + } + + const u8* startPos; + const u8* endPos; + const u8* currentPos; + s16 coEfficients[16]; + s16 nibbles[14]; + s16 pcm[14]; + s16 hist1; + s16 hist2; + const u8* loopStart; + u16 loopOffset; + s16 loop_hist1; + s16 loop_hist2; +}; + +class GuiSoundDecoderBNS : public GuiSoundDecoder +{ +protected: + GuiSoundDecoderBNS(const u8 * snd, u32 len, bool snd_is_allocated) + { + sound = snd; + is_running = false; + is_allocated = snd_is_allocated; + + const u8 *in_ptr = sound; + + ///////////////// + // READ HEADER // + ///////////////// + if(be32inc(in_ptr) != 0x424E5320 /*'BNS '*/) throw("Not a BNS"); + + in_ptr += 4; // skip 4 byte + + u32 bnssize = be32inc(in_ptr); + if(bnssize != len) throw("Wrong size"); + + in_ptr += 4; // skip unknown1 + + const u8* infoStart = sound + be32inc(in_ptr); + in_ptr+=4; // skip const u8* infoEnd = infoStart + be32inc(in_ptr); + + channel[0].startPos = sound + be32inc(in_ptr) + 8; + channel[0].endPos = channel[0].startPos + be32inc(in_ptr) - 8; + + /////////////// + // READ INFO // + /////////////// + in_ptr = infoStart + 8; // skip 'INFO' and Infosize + + in_ptr++; // skip u8 codeType = *in_ptr++; + + in_ptr++; // u8 loopFlag = *in_ptr++; + + channelCount = *in_ptr++; + + in_ptr++; // skip unknown byte + + sampleRate = be16inc(in_ptr); + + in_ptr+=2; // skip unknown word + + u32 loopStart = be32inc(in_ptr); + channel[0].loopStart = channel[0].startPos + ((loopStart/14)*8);//LoopPos to BlockStart + channel[1].loopStart = channel[1].startPos + ((loopStart/14)*8); + channel[0].loopOffset = channel[1].loopOffset = loopStart%14; + + in_ptr+=4; // skip u32 SampleCount = be32inc(in_ptr); + + in_ptr+=24; // skip unknown Bytes + + if(channelCount == 2) + { + in_ptr+=4; // skip unknown long + u32 ChannelSplit = be32inc(in_ptr); + + in_ptr+=8; // skip 2x unknown long + + channel[1].endPos = channel[0].endPos; + channel[0].endPos = channel[1].startPos = channel[0].startPos + ChannelSplit; + + channel[1].loopStart = channel[1].startPos + (channel[0].loopStart - channel[0].startPos); + } + for (int a = 0; a < 16; a++) + { + channel[0].coEfficients[a] = (s16)be16inc(in_ptr); + } + if(channelCount == 2) + { + in_ptr+=16; // skip 16 byte + for (int a = 0; a < 16; a++) + { + channel[1].coEfficients[a] = (s16)be16inc(in_ptr); + } + } + channel[0].Reset(); + channel[1].Reset(); + currentBlockPos = 14; + } +public: + ~GuiSoundDecoderBNS() + { + while(is_running) usleep(50); + if(is_allocated) delete [] sound; + } + static GuiSoundDecoder *Create(const u8 * snd, u32 len, bool snd_is_allocated) + { + if(snd && len>4 && snd[0]=='B' && snd[1]=='N' && snd[2]=='S' && snd[3]==' ') + return new GuiSoundDecoderBNS(snd, len, snd_is_allocated); + return NULL; + } + s32 GetFormat() + { + return channelCount==2 ? VOICE_STEREO_16BIT : VOICE_MONO_16BIT; + } + s32 GetSampleRate() + { + return sampleRate; + } + /* Read reads data from stream to buffer + return: >0 = readed bytes; + 0 = EOF; + <0 = Error; + */ + int Read(u8 * buffer, int buffer_size) + { + is_running = true; + u8 *write_pos = buffer; + u8 *write_end = buffer+buffer_size; + + for(;;) + { + if(currentBlockPos >= 14) + { + int Offset = channel[0].DecodeNextBlock(); + if(Offset<0 || (channelCount == 2 && channel[1].DecodeNextBlock()<0) ) + { + is_running = false; + return write_pos-buffer; + } + currentBlockPos = Offset; + } + for(;currentBlockPos < 14; ++currentBlockPos) + { + if(write_pos >= write_end) + { + is_running = false; + return write_pos-buffer; + } + *((s16*)write_pos) = channel[0].pcm[currentBlockPos]; + write_pos+=2; + if(channelCount==2) // stereo + { + *((s16*)write_pos) = channel[1].pcm[currentBlockPos]; + write_pos+=2; + } + } + } + is_running = false; + return 0; + } + int Rewind() + { + channel[0].Reset(); + channel[1].Reset(); + currentBlockPos = 14; + return 0; + } +private: + const u8 *sound; + bool is_allocated; + bool is_running; + chanel_t channel[2]; + u16 currentBlockPos; + u16 channelCount; + u32 sampleRate; +// u16 loopOffset; +// u16 bytePerSample; +// const u8 *soundDataStart; +// const u8 *soundDataEnd; +// u32 soundDataLen; +}; +REGISTER_GUI_SOUND_DECODER(GuiSoundDecoderBNS); diff --git a/source/libwiigui/gui_sound_decoder_mpg.cpp b/source/libwiigui/gui_sound_decoder_mpg.cpp new file mode 100644 index 00000000..fa3031c8 --- /dev/null +++ b/source/libwiigui/gui_sound_decoder_mpg.cpp @@ -0,0 +1,214 @@ +/**************************************************************************** + * libwiigui + * + * Tantric 2009 + * + * gui_sound_plugin_mpg.cpp + * + * by ardi 2009 + * + * Decoder for MPEG-Audio Mpeg-1/-2 Layer I,II and III with libmad + * + * GUI class definitions + ***************************************************************************/ + +#include +#include +#include +#include +#include +#include + + +#include "gui_sound_decoder.h" + +static inline s16 FixedToShort(mad_fixed_t Fixed) +{ + /* Clipping */ + if(Fixed>=MAD_F_ONE) + return(SHRT_MAX); + if(Fixed<=-MAD_F_ONE) + return(-SHRT_MAX); + + Fixed=Fixed>>(MAD_F_FRACBITS-15); + return((s16)Fixed); +} + +#define ADMA_BUFFERSIZE (8192) +#define DATABUFFER_SIZE (32768) +// http://www.fr-an.de/fragen/v06/02_01.htm + + +class GuiSoundDecoderMPG : public GuiSoundDecoder +{ +protected: + GuiSoundDecoderMPG(const u8 * snd, u32 len, bool snd_is_allocated) + { + sound = snd; + length = len; + is_allocated = snd_is_allocated; + // Init mad-structures + mad_stream_init(&madStream); + mad_stream_buffer(&madStream, sound, length); + mad_frame_init(&madFrame); + mad_synth_init(&madSynth); + madSynthPcmPos = 0; + mad_timer_reset(&madTimer); + guardBuffer = NULL; + is_running = false; + + // decode first Frame + if(DecodeFirstFrame()) + { + mad_synth_finish(&madSynth); + mad_frame_finish(&madFrame); + mad_stream_finish(&madStream); + throw("Stream Error"); + } + } +public: + ~GuiSoundDecoderMPG() + { + while(is_running) usleep(50); + mad_synth_finish(&madSynth); + mad_frame_finish(&madFrame); + mad_stream_finish(&madStream); + delete [] guardBuffer; + if(is_allocated) delete [] sound; + } + static GuiSoundDecoder *Create(const u8 * snd, u32 len, bool snd_is_allocated) + { + struct mad_stream madStream; + struct mad_header madHeader; + mad_stream_init(&madStream); + mad_stream_buffer(&madStream, snd, len); + mad_header_init(&madHeader); + s32 ret = mad_header_decode(&madHeader, &madStream); + if(ret == 0 || madStream.error==MAD_ERROR_LOSTSYNC) // LOSTSYNC in first call is ok + { + int i; + for(i=0; i<4 && mad_header_decode(&madHeader, &madStream)==0; i++); + if( i == 4 ) + { + mad_header_finish(&madHeader); + mad_stream_finish(&madStream); + return new GuiSoundDecoderMPG(snd, len, snd_is_allocated); + } + } + mad_header_finish(&madHeader); + mad_stream_finish(&madStream); + return NULL; + } + s32 GetFormat() + { + return MAD_NCHANNELS(&madFrame.header)==2 ? VOICE_STEREO_16BIT : VOICE_MONO_16BIT; + } + s32 GetSampleRate() + { + return madFrame.header.samplerate; + } + /* Read reads data from stream to buffer + return: >0 = readed bytes; + 0 = EOF; + <0 = Error; + */ + int Read(u8 * buffer, int buffer_size) + { + is_running = true; + if(MAD_NCHANNELS(&madFrame.header)==2) // stereo + buffer_size &= ~0x0003; // make size to a kind of 4 + else + buffer_size &= ~0x0001; // make size to a kind of 2 + u8 *write_pos = buffer; + u8 *write_end = buffer+buffer_size; + + for(;;) + { + for(;madSynthPcmPos < madSynth.pcm.length; ++madSynthPcmPos) + { + if(write_pos >= write_end) + { + is_running = false; + return write_pos-buffer; + } + *((s16*)write_pos) = FixedToShort(madSynth.pcm.samples[0][madSynthPcmPos]); write_pos+=2; + if(MAD_NCHANNELS(&madFrame.header)==2) // stereo + { + *((s16*)write_pos) = FixedToShort(madSynth.pcm.samples[1][madSynthPcmPos]); write_pos+=2; + } + } + + madStream.error = MAD_ERROR_NONE; + if(mad_frame_decode(&madFrame,&madStream)) + { + if(MAD_RECOVERABLE(madStream.error)) + { + if(madStream.error!=MAD_ERROR_LOSTSYNC || !guardBuffer) + continue; + } + else if(madStream.error==MAD_ERROR_BUFLEN) + { + if(!guardBuffer) + { + u32 guardLen = (madStream.bufend-madStream.next_frame); + guardBuffer = new(std::nothrow) u8[guardLen + MAD_BUFFER_GUARD]; + if(guardBuffer) + { + memcpy(guardBuffer, madStream.next_frame, guardLen); + memset(guardBuffer+guardLen, 0, MAD_BUFFER_GUARD); + mad_stream_buffer(&madStream, guardBuffer, guardLen + MAD_BUFFER_GUARD); + continue; + } + } + } + break; + } + mad_timer_add(&madTimer,madFrame.header.duration); + mad_synth_frame(&madSynth,&madFrame); + madSynthPcmPos = 0; + } + is_running = false; + return write_pos-buffer; + } + int Rewind() + { + while(is_running) usleep(50); + delete [] guardBuffer; guardBuffer = NULL; + mad_stream_buffer(&madStream, sound, length); + mad_synth_finish(&madSynth); + mad_synth_init(&madSynth); + madSynthPcmPos = 0; + mad_timer_reset(&madTimer); + // decode first Frame + return DecodeFirstFrame(); + } +private: + int DecodeFirstFrame() + { + for(;;) + { + madStream.error = MAD_ERROR_NONE; + if(mad_frame_decode(&madFrame,&madStream)) + { + if(MAD_RECOVERABLE(madStream.error)) + continue; + else + return -1; + } + mad_timer_add(&madTimer,madFrame.header.duration); + mad_synth_frame(&madSynth,&madFrame); + return 0; + } + } + const u8 *sound; + u32 length; + bool is_allocated; + struct mad_stream madStream; + struct mad_frame madFrame; + struct mad_synth madSynth; + u16 madSynthPcmPos; + mad_timer_t madTimer; + u8 *guardBuffer; + bool is_running; +}; +REGISTER_GUI_SOUND_DECODER(GuiSoundDecoderMPG); diff --git a/source/libwiigui/gui_sound_decoder_ogg.cpp b/source/libwiigui/gui_sound_decoder_ogg.cpp new file mode 100644 index 00000000..94b6ce7b --- /dev/null +++ b/source/libwiigui/gui_sound_decoder_ogg.cpp @@ -0,0 +1,94 @@ +/**************************************************************************** + * libwiigui + * + * Tantric 2009 + * + * gui_sound_plugin_ogg.cpp + * + * by ardi 2009 + * + * Decoder for ogg-vorbis with libtremor + * + * GUI class definitions + ***************************************************************************/ + +#include +#include +#include +#include + +#include "gui_sound_decoder.h" + +class GuiSoundDecoderOGG : public GuiSoundDecoder +{ +protected: + GuiSoundDecoderOGG(const u8 * snd, u32 len, bool snd_is_allocated) + { + sound = snd; + is_allocated = snd_is_allocated; + ogg_fd = mem_open((char *)snd, len); + if(ogg_fd < 0) throw("mem open failed"); + + if (ov_open((FILE*)&ogg_fd, &ogg_file, NULL, 0) < 0) + { + mem_close(ogg_fd); + throw("ogg open failed"); + } + ogg_info = ov_info(&ogg_file, -1); + bitstream = 0; + is_running = false; + } +public: + ~GuiSoundDecoderOGG() + { + while(is_running) usleep(50); + ov_clear(&ogg_file); + if(is_allocated) delete [] sound; + } + static GuiSoundDecoder *Create(const u8 * snd, u32 len, bool snd_is_allocated) + { + if(snd && len>4 && snd[0]=='O' && snd[1]=='g' && snd[2]=='g' && snd[3]=='S') + return new GuiSoundDecoderOGG(snd, len, snd_is_allocated); + return NULL; + } + s32 GetFormat() + { + return ogg_info->channels==2 ? VOICE_STEREO_16BIT : VOICE_MONO_16BIT; + } + s32 GetSampleRate() + { + return ogg_info->rate; + } + /* Read reads data from stream to buffer + return: >0 = readed bytes; + 0 = EOF; + <0 = Error; + */ + int Read(u8 * buffer, int buffer_size) + { + is_running = true; + int ret = ov_read(&ogg_file, (char *)buffer, buffer_size, &bitstream); + if (ret < 0) + { + /* error in the stream. Not a problem, just reporting it in + case we (the app) cares. In this case, we don't. */ + if (ret != OV_HOLE) + ret = 0; // we says EOF + } + is_running = false; + return ret; + } + int Rewind() + { + return ov_time_seek(&ogg_file, 0); + } +private: + const u8 *sound; + bool is_allocated; + int ogg_fd; + OggVorbis_File ogg_file; + vorbis_info *ogg_info; + int bitstream; + bool is_running; +}; +REGISTER_GUI_SOUND_DECODER(GuiSoundDecoderOGG); diff --git a/source/libwiigui/gui_sound_decoder_wav.cpp b/source/libwiigui/gui_sound_decoder_wav.cpp new file mode 100644 index 00000000..7a759356 --- /dev/null +++ b/source/libwiigui/gui_sound_decoder_wav.cpp @@ -0,0 +1,236 @@ +/**************************************************************************** + * libwiigui + * + * Tantric 2009 + * + * gui_sound_plugin_wav.cpp + * + * by ardi 2009 + * + * Decoder for WAVE PCM + * + * GUI class definitions + ***************************************************************************/ + +#include +#include +#include +#include + +#include "gui_sound_decoder.h" + +typedef struct +{ + u32 cueID; + u32 len; + u32 loops; +}plst_t; +typedef struct +{ + const u8 *start; + const u8 *end; + u32 loops; +}playlist_t; +class GuiSoundDecoderWAV : public GuiSoundDecoder +{ +protected: + GuiSoundDecoderWAV(const u8 * snd, u32 len, bool snd_is_allocated) + { + sound = snd; + is_running = false; + is_allocated = snd_is_allocated; + + const u8 *in_ptr = sound; + + if(be32inc(in_ptr) != 0x52494646 /*'RIFF' (WAV)*/) throw("Not a WAV"); + + u32 riffsize = le32inc(in_ptr); + if(riffsize > (len-8)) throw("Wrong size"); + + if(be32inc(in_ptr) != 0x57415645 /*'WAVE'*/) throw("No WAVE-Tag"); + + if(be32inc(in_ptr) != 0x666D7420 /*'fmt '*/) throw("No fmt-Tag"); + + u32 fmtLen = le32inc(in_ptr); + + if(le16inc(in_ptr) != 1) throw("Not PCM data"); + + channelCount = le16inc(in_ptr); + if(channelCount < 1 || channelCount > 2) throw("only mono or stereo"); + + sampleRate = le32inc(in_ptr); + + in_ptr += 6; // skip and + + bytePerSample = (le16inc(in_ptr)+7)/8; + if(bytePerSample < 1 || bytePerSample > 2) throw("only 1-16 bit/Sample"); + + in_ptr += fmtLen-16; + + if(be32inc(in_ptr) != 0x64617461 /*'data'*/) throw("No data-Tag"); + + + soundDataStart = in_ptr+4; + soundDataEnd = soundDataStart + le32(in_ptr); + + in_ptr = soundDataEnd; + + std::map cue; + std::vectorplst; + + if(((u32)in_ptr) & 0x0001UL) in_ptr++; + while((in_ptr+4) < (sound + riffsize)) + { + u32 tag = be32inc(in_ptr); + switch(tag) + { + case 0x63756520 /*'cue '*/: + in_ptr += 4; // skip size + for(u32 count = le32inc(in_ptr); count>0; count--) + { + u32 ID = be32inc(in_ptr); + in_ptr += 4; // skip dwPosition + if(be32inc(in_ptr) == 0x64617461 /*'data'*/) + { + in_ptr += 8; // skip chunkStart - dwBlockStart + cue[ID] = le32inc(in_ptr); + } + else + in_ptr += 12; // skip chunkStart - SammpleOffset + } + break; + case 0x706C7374 /*' plst'*/: + in_ptr += 4; // skip size + for(u32 count = le32inc(in_ptr); count>0; count--) + plst.push_back((plst_t){le32inc(in_ptr), le32inc(in_ptr), le32inc(in_ptr)}); + break; + default: + in_ptr -= 2; + break; + } + } + for(std::vector::iterator i = plst.begin(); i != plst.end(); ++i) + { + const u8 *start = soundDataStart + cue[i->cueID]; + const u8 *end = soundDataStart + (i->len*bytePerSample*channelCount); + u32 loops = i->loops; + playlist.push_back((playlist_t){start,end,loops}); + } + if(playlist.size() == 0) + { + playlist.push_back((playlist_t){soundDataStart, soundDataEnd, 1}); + } + Rewind(); + } +public: + ~GuiSoundDecoderWAV() + { + while(is_running) usleep(50); + if(is_allocated) delete [] sound; + } + static GuiSoundDecoder *Create(const u8 * snd, u32 len, bool snd_is_allocated) + { + if(snd && len>4 && snd[0]=='R' && snd[1]=='I' && snd[2]=='F' && snd[3]=='F' + && snd[8]=='W' && snd[9]=='A' && snd[10]=='V' && snd[11]=='E') + return new GuiSoundDecoderWAV(snd, len, snd_is_allocated); + return NULL; + } + s32 GetFormat() + { + if(bytePerSample == 2) + return channelCount==2 ? VOICE_STEREO_16BIT : VOICE_MONO_16BIT; + else + return channelCount==2 ? VOICE_STEREO_8BIT : VOICE_MONO_8BIT; + } + s32 GetSampleRate() + { + return sampleRate; + } + /* Read reads data from stream to buffer + return: >0 = readed bytes; + 0 = EOF; + <0 = Error; + */ + int Read(u8 * buffer, int buffer_size) + { + is_running = true; + u8 *write_pos = buffer; + u8 *write_end = buffer+buffer_size; + + for(;;) + { + while(currentPos < currentEnd) + { + if(write_pos >= write_end) + { + is_running = false; + return write_pos-buffer; + } + if(bytePerSample == 2) + { + *((s16*)write_pos) = le16inc(currentPos); + write_pos+=2; + if(channelCount==2) // stereo + { + *((s16*)write_pos) = le16inc(currentPos); + write_pos+=2; + } + } + else + { + *write_pos++ = *currentPos++; + if(channelCount==2) // stereo + *write_pos++ = *currentPos++; + } + } + if(currentLoops>1) + { + currentLoops--; + currentPos = currentStart; + continue; + } + if(currentPlaylist != playlist.end()) + currentPlaylist++; + if(currentPlaylist != playlist.end()) + { + currentStart = currentPos = currentPlaylist->start; + currentEnd = currentPlaylist->end; + currentLoops = currentPlaylist->loops; + continue; + } + else + { + is_running = false; + return write_pos-buffer; + } + } + is_running = false; + return 0; + } + int Rewind() + { + currentPlaylist = playlist.begin(); + currentStart = currentPos = currentPlaylist->start; + currentEnd = currentPlaylist->end; + currentLoops = currentPlaylist->loops; + return 0; + } +private: + const u8 *sound; + bool is_allocated; + bool is_running; + + u16 channelCount; + u32 sampleRate; + u16 bytePerSample; + const u8 *soundDataStart; + const u8 *soundDataEnd; + std::vector playlist; + std::vector::iterator currentPlaylist; + const u8 *currentStart; + const u8 *currentEnd; + u32 currentLoops; + const u8 *currentPos; + +}; +REGISTER_GUI_SOUND_DECODER(GuiSoundDecoderWAV); diff --git a/source/listfiles.c b/source/listfiles.c index 92a7ef75..5f831d67 100644 --- a/source/listfiles.c +++ b/source/listfiles.c @@ -40,7 +40,7 @@ bool subfoldercreate(const char * fullpath) { strlcpy(dir, fullpath, sizeof(dir)); len = strlen(dir); - if(len && len< sizeof(dir)-2 && dir[len-1] != '/'); + if(len && len< sizeof(dir)-2 && dir[len-1] != '/') { dir[len++] = '/'; dir[len] = '\0'; @@ -63,7 +63,42 @@ bool subfoldercreate(const char * fullpath) { } return true; } - +bool subfolderremove(const char * fullpath, const char*fp) { + struct stat st; + if (stat(fullpath, &st) != 0) // fullpath not exist? + return false; + if(S_ISDIR(st.st_mode)) + { + DIR_ITER *dir = NULL; + char filename[256]; + bool cont = true; + while(cont) + { + cont = false; + dir = diropen(fullpath); + if(dir) + { + char* bind = fullpath[strlen(fullpath)-1] == '/' ? "":"/"; + while (dirnext(dir,filename,&st) == 0) + { + if (strcmp(filename,".") != 0 && strcmp(filename,"..") != 0) + { + char currentname[256]; + if(S_ISDIR(st.st_mode)) + snprintf(currentname, sizeof(currentname), "%s%s%s/", fullpath, bind, filename); + else + snprintf(currentname, sizeof(currentname), "%s%s%s", fullpath, bind, filename); + subfolderremove(currentname, fp); + cont = true; + break; + } + } + dirclose(dir); + } + } + } + return unlink(fullpath) == 0; +} char * GetFileName(int i) { return alldirfiles[i]; } diff --git a/source/lstub.c b/source/lstub.c index f117dbd7..5ae4121f 100644 --- a/source/lstub.c +++ b/source/lstub.c @@ -102,7 +102,7 @@ u64 getStubDest() char *stub = (char *)0x800024C6; - char ret[8]; + char ret[9]; u64 retu =0; ret[0] = stub[0]; diff --git a/source/main.h b/source/main.h index f2588132..fb320832 100644 --- a/source/main.h +++ b/source/main.h @@ -10,7 +10,6 @@ #include "FreeTypeGX.h" -extern struct SSettings Settings; void DefaultSettings(); extern FreeTypeGX *fontSystem; diff --git a/source/menu.cpp b/source/menu.cpp index 096a1c0f..4e344189 100644 --- a/source/menu.cpp +++ b/source/menu.cpp @@ -62,6 +62,8 @@ GuiImageData * pointer[4]; GuiImage * bgImg = NULL; GuiImageData * background = NULL; GuiSound * bgMusic = NULL; +GuiSound *btnClick2 = NULL; + float gamesize; int currentMenu; int idiotFlag=-1; @@ -371,8 +373,10 @@ int MenuDiscList() { } - GuiSound btnSoundOver(button_over_pcm, button_over_pcm_size, SOUND_PCM, Settings.sfxvolume); - GuiSound btnClick(button_click2_pcm, button_click2_pcm_size, SOUND_PCM, Settings.sfxvolume); + GuiSound btnSoundOver(button_over_pcm, button_over_pcm_size, Settings.sfxvolume); + // because destroy GuiSound must wait while sound playing is finished, we use a global sound + if(!btnClick2) btnClick2=new GuiSound(button_click2_pcm, button_click2_pcm_size, Settings.sfxvolume); + // GuiSound btnClick(button_click2_pcm, button_click2_pcm_size, Settings.sfxvolume); snprintf(imgPath, sizeof(imgPath), "%sbutton_install.png", CFG.theme_path); GuiImageData btnInstall(imgPath, button_install_png); @@ -485,7 +489,7 @@ int MenuDiscList() { installBtnImg.SetWidescreen(CFG.widescreen); installBtnImgOver.SetWidescreen(CFG.widescreen); - GuiButton installBtn(&installBtnImg, &installBtnImgOver, ALIGN_LEFT, ALIGN_TOP, THEME.install_x, THEME.install_y, &trigA, &btnSoundOver, &btnClick, 1, &installBtnTT,24,-30, 0,5); + GuiButton installBtn(&installBtnImg, &installBtnImgOver, ALIGN_LEFT, ALIGN_TOP, THEME.install_x, THEME.install_y, &trigA, &btnSoundOver, btnClick2, 1, &installBtnTT,24,-30, 0,5); GuiTooltip settingsBtnTT(tr("Settings")); @@ -496,7 +500,7 @@ int MenuDiscList() { settingsBtnImg.SetWidescreen(CFG.widescreen); GuiImage settingsBtnImgOver(&btnSettingsOver); settingsBtnImgOver.SetWidescreen(CFG.widescreen); - GuiButton settingsBtn(&settingsBtnImg,&settingsBtnImgOver, 0, 3, THEME.setting_x, THEME.setting_y, &trigA, &btnSoundOver, &btnClick,1,&settingsBtnTT,65,-30,0,5); + GuiButton settingsBtn(&settingsBtnImg,&settingsBtnImgOver, 0, 3, THEME.setting_x, THEME.setting_y, &trigA, &btnSoundOver, btnClick2,1,&settingsBtnTT,65,-30,0,5); GuiTooltip homeBtnTT(tr("Back to HBC or Wii Menu")); if (Settings.wsprompt == yes) @@ -506,7 +510,7 @@ int MenuDiscList() { homeBtnImg.SetWidescreen(CFG.widescreen); GuiImage homeBtnImgOver(&btnhomeOver); homeBtnImgOver.SetWidescreen(CFG.widescreen); - GuiButton homeBtn(&homeBtnImg,&homeBtnImgOver, 0, 3, THEME.home_x, THEME.home_y, &trigA, &btnSoundOver, &btnClick,1,&homeBtnTT,15,-30,1,5); + GuiButton homeBtn(&homeBtnImg,&homeBtnImgOver, 0, 3, THEME.home_x, THEME.home_y, &trigA, &btnSoundOver, btnClick2,1,&homeBtnTT,15,-30,1,5); homeBtn.RemoveSoundClick(); homeBtn.SetTrigger(&trigHome); @@ -518,7 +522,7 @@ int MenuDiscList() { GuiImage poweroffBtnImgOver(&btnpwroffOver); poweroffBtnImg.SetWidescreen(CFG.widescreen); poweroffBtnImgOver.SetWidescreen(CFG.widescreen); - GuiButton poweroffBtn(&poweroffBtnImg,&poweroffBtnImgOver, 0, 3, THEME.power_x, THEME.power_y, &trigA, &btnSoundOver, &btnClick,1,&poweroffBtnTT,-10,-30,1,5); + GuiButton poweroffBtn(&poweroffBtnImg,&poweroffBtnImgOver, 0, 3, THEME.power_x, THEME.power_y, &trigA, &btnSoundOver, btnClick2,1,&poweroffBtnTT,-10,-30,1,5); GuiTooltip sdcardBtnTT(tr("Reload SD")); @@ -529,16 +533,16 @@ int MenuDiscList() { GuiImage sdcardImgOver(&btnsdcardOver); sdcardImg.SetWidescreen(CFG.widescreen); sdcardImgOver.SetWidescreen(CFG.widescreen); - GuiButton sdcardBtn(&sdcardImg,&sdcardImgOver, 0, 3, THEME.sdcard_x, THEME.sdcard_y, &trigA, &btnSoundOver, &btnClick,1,&sdcardBtnTT,15,-30,0,5); + GuiButton sdcardBtn(&sdcardImg,&sdcardImgOver, 0, 3, THEME.sdcard_x, THEME.sdcard_y, &trigA, &btnSoundOver, btnClick2,1,&sdcardBtnTT,15,-30,0,5); GuiButton gameInfo(0,0); gameInfo.SetTrigger(&trig2); - gameInfo.SetSoundClick(&btnClick); + gameInfo.SetSoundClick(btnClick2); GuiImage wiiBtnImg(&dataID); wiiBtnImg.SetWidescreen(CFG.widescreen); - GuiButton wiiBtn(&wiiBtnImg,&wiiBtnImg, 0, 4, 0, -10, &trigA, &btnSoundOver, &btnClick,0); + GuiButton wiiBtn(&wiiBtnImg,&wiiBtnImg, 0, 4, 0, -10, &trigA, &btnSoundOver, btnClick2,0); GuiTooltip favoriteBtnTT(tr("Display favorites")); if (Settings.wsprompt == yes) @@ -550,7 +554,7 @@ int MenuDiscList() { GuiImage favoriteBtnImg_g(&imgfavIcon_gray); if(favoriteBtnImg_g.GetImage() == NULL) { favoriteBtnImg_g = favoriteBtnImg; favoriteBtnImg_g.SetGrayscale();} favoriteBtnImg_g.SetWidescreen(CFG.widescreen); - GuiButton favoriteBtn(&favoriteBtnImg_g,&favoriteBtnImg_g, ALIGN_LEFT, ALIGN_TOP, THEME.gamelist_favorite_x, THEME.gamelist_favorite_y, &trigA, &btnSoundOver, &btnClick,1, &favoriteBtnTT, -15, 52, 0, 3); + GuiButton favoriteBtn(&favoriteBtnImg_g,&favoriteBtnImg_g, ALIGN_LEFT, ALIGN_TOP, THEME.gamelist_favorite_x, THEME.gamelist_favorite_y, &trigA, &btnSoundOver, btnClick2,1, &favoriteBtnTT, -15, 52, 0, 3); favoriteBtn.SetAlpha(180); GuiTooltip searchBtnTT(tr("Set Search-Filter")); @@ -563,7 +567,7 @@ int MenuDiscList() { GuiImage searchBtnImg_g(&imgsearchIcon_gray); if(searchBtnImg_g.GetImage() == NULL) { searchBtnImg_g = searchBtnImg; searchBtnImg_g.SetGrayscale();} searchBtnImg_g.SetWidescreen(CFG.widescreen); - GuiButton searchBtn(&searchBtnImg_g,&searchBtnImg_g, ALIGN_LEFT, ALIGN_TOP, THEME.gamelist_search_x, THEME.gamelist_search_y, &trigA, &btnSoundOver, &btnClick,1, &searchBtnTT, -15, 52, 0, 3); + GuiButton searchBtn(&searchBtnImg_g,&searchBtnImg_g, ALIGN_LEFT, ALIGN_TOP, THEME.gamelist_search_x, THEME.gamelist_search_y, &trigA, &btnSoundOver, btnClick2,1, &searchBtnTT, -15, 52, 0, 3); searchBtn.SetAlpha(180); GuiTooltip abcBtnTT(Settings.fave ? tr("Sort by rank") : tr("Sort alphabetically")); @@ -576,7 +580,7 @@ int MenuDiscList() { GuiImage abcBtnImg_g(Settings.fave ? &imgrankIcon_gray : &imgabcIcon_gray); if(abcBtnImg_g.GetImage() == NULL) { abcBtnImg_g = abcBtnImg; abcBtnImg_g.SetGrayscale();} abcBtnImg_g.SetWidescreen(CFG.widescreen); - GuiButton abcBtn(&abcBtnImg_g,&abcBtnImg_g, ALIGN_LEFT, ALIGN_TOP, THEME.gamelist_abc_x, THEME.gamelist_abc_y, &trigA, &btnSoundOver, &btnClick,1,&abcBtnTT, -15, 52, 0, 3); + GuiButton abcBtn(&abcBtnImg_g,&abcBtnImg_g, ALIGN_LEFT, ALIGN_TOP, THEME.gamelist_abc_x, THEME.gamelist_abc_y, &trigA, &btnSoundOver, btnClick2,1,&abcBtnTT, -15, 52, 0, 3); abcBtn.SetAlpha(180); GuiTooltip countBtnTT(tr("Sort order by most played")); @@ -589,7 +593,7 @@ int MenuDiscList() { GuiImage countBtnImg_g(&imgplayCountIcon_gray); if(countBtnImg_g.GetImage() == NULL) { countBtnImg_g = countBtnImg; countBtnImg_g.SetGrayscale();} countBtnImg_g.SetWidescreen(CFG.widescreen); - GuiButton countBtn(&countBtnImg_g,&countBtnImg_g, ALIGN_LEFT, ALIGN_TOP, THEME.gamelist_count_x, THEME.gamelist_count_y, &trigA, &btnSoundOver, &btnClick,1, &countBtnTT, -15, 52, 0, 3); + GuiButton countBtn(&countBtnImg_g,&countBtnImg_g, ALIGN_LEFT, ALIGN_TOP, THEME.gamelist_count_x, THEME.gamelist_count_y, &trigA, &btnSoundOver, btnClick2,1, &countBtnTT, -15, 52, 0, 3); countBtn.SetAlpha(180); GuiTooltip listBtnTT(tr("Display as a list")); @@ -602,7 +606,7 @@ int MenuDiscList() { GuiImage listBtnImg_g(&imgarrangeList_gray); if(listBtnImg_g.GetImage() == NULL) { listBtnImg_g = listBtnImg; listBtnImg_g.SetGrayscale();} listBtnImg_g.SetWidescreen(CFG.widescreen); - GuiButton listBtn(&listBtnImg_g,&listBtnImg_g, ALIGN_LEFT, ALIGN_TOP, THEME.gamelist_list_x, THEME.gamelist_list_y, &trigA, &btnSoundOver, &btnClick,1, &listBtnTT, 15, 52, 1, 3); + GuiButton listBtn(&listBtnImg_g,&listBtnImg_g, ALIGN_LEFT, ALIGN_TOP, THEME.gamelist_list_x, THEME.gamelist_list_y, &trigA, &btnSoundOver, btnClick2,1, &listBtnTT, 15, 52, 1, 3); listBtn.SetAlpha(180); GuiTooltip gridBtnTT(tr("Display as a grid")); @@ -615,7 +619,7 @@ int MenuDiscList() { GuiImage gridBtnImg_g(&imgarrangeGrid_gray); if(gridBtnImg_g.GetImage() == NULL) { gridBtnImg_g = gridBtnImg; gridBtnImg_g.SetGrayscale();} gridBtnImg_g.SetWidescreen(CFG.widescreen); - GuiButton gridBtn(&gridBtnImg_g,&gridBtnImg_g, ALIGN_LEFT, ALIGN_TOP, THEME.gamelist_grid_x, THEME.gamelist_grid_y, &trigA, &btnSoundOver, &btnClick,1, &gridBtnTT, 15, 52, 1, 3); + GuiButton gridBtn(&gridBtnImg_g,&gridBtnImg_g, ALIGN_LEFT, ALIGN_TOP, THEME.gamelist_grid_x, THEME.gamelist_grid_y, &trigA, &btnSoundOver, btnClick2,1, &gridBtnTT, 15, 52, 1, 3); gridBtn.SetAlpha(180); GuiTooltip carouselBtnTT(tr("Display as a carousel")); @@ -628,7 +632,7 @@ int MenuDiscList() { GuiImage carouselBtnImg_g(&imgarrangeCarousel_gray); if(carouselBtnImg_g.GetImage() == NULL) { carouselBtnImg_g = carouselBtnImg; carouselBtnImg_g.SetGrayscale();} carouselBtnImg_g.SetWidescreen(CFG.widescreen); - GuiButton carouselBtn(&carouselBtnImg_g,&carouselBtnImg_g, ALIGN_LEFT, ALIGN_TOP, THEME.gamelist_carousel_x, THEME.gamelist_carousel_y, &trigA, &btnSoundOver, &btnClick,1, &carouselBtnTT, 15, 52, 1, 3); + GuiButton carouselBtn(&carouselBtnImg_g,&carouselBtnImg_g, ALIGN_LEFT, ALIGN_TOP, THEME.gamelist_carousel_x, THEME.gamelist_carousel_y, &trigA, &btnSoundOver, btnClick2,1, &carouselBtnTT, 15, 52, 1, 3); carouselBtn.SetAlpha(180); GuiTooltip dvdBtnTT(tr("Mount DVD drive")); @@ -640,7 +644,7 @@ int MenuDiscList() { GuiImage dvdBtnImg_g(dvdBtnImg); //dvdBtnImg_g.SetGrayscale(); // GuiImage carouselBtnImg_g(&imgarrangeCarousel_gray); dvdBtnImg_g.SetWidescreen(CFG.widescreen); - GuiButton dvdBtn(&dvdBtnImg_g,&dvdBtnImg_g, ALIGN_LEFT, ALIGN_TOP, THEME.gamelist_dvd_x, THEME.gamelist_dvd_y, &trigA, &btnSoundOver, &btnClick,1, &dvdBtnTT, 15, 52, 1, 3); + GuiButton dvdBtn(&dvdBtnImg_g,&dvdBtnImg_g, ALIGN_LEFT, ALIGN_TOP, THEME.gamelist_dvd_x, THEME.gamelist_dvd_y, &trigA, &btnSoundOver, btnClick2,1, &dvdBtnTT, 15, 52, 1, 3); dvdBtn.SetAlpha(180); GuiTooltip homebrewBtnTT(tr("Homebrew Launcher")); @@ -651,7 +655,7 @@ int MenuDiscList() { GuiImage homebrewImgOver(&homebrewImgDataOver); homebrewImg.SetWidescreen(CFG.widescreen); homebrewImgOver.SetWidescreen(CFG.widescreen); - GuiButton homebrewBtn(&homebrewImg,&homebrewImgOver, ALIGN_LEFT, ALIGN_TOP, THEME.homebrew_x, THEME.homebrew_y, &trigA, &btnSoundOver, &btnClick,1,&homebrewBtnTT,15,-30,1,5); + GuiButton homebrewBtn(&homebrewImg,&homebrewImgOver, ALIGN_LEFT, ALIGN_TOP, THEME.homebrew_x, THEME.homebrew_y, &trigA, &btnSoundOver, btnClick2,1,&homebrewBtnTT,15,-30,1,5); if (Settings.fave) { favoriteBtn.SetImage(&favoriteBtnImg); @@ -972,16 +976,9 @@ int MenuDiscList() { } else if (homeBtn.GetState() == STATE_CLICKED) { gprintf("\n\thomeBtn clicked"); - s32 thetimeofbg = bgMusic->GetPlayTime(); - bgMusic->Stop(); + bgMusic->Pause(); choice = WindowExitPrompt(tr("Exit USB Loader GX?"),0, tr("Back to Loader"),tr("Wii Menu"),tr("Back"),0); - if (!strcmp("", Settings.oggload_path) || !strcmp("notset", Settings.ogg_path)) { - bgMusic->Play(); - } else { - bgMusic->PlayOggFile(Settings.ogg_path); - } - bgMusic->SetPlayTime(thetimeofbg); - SetVolumeOgg(255*(Settings.volume/100.0)); + bgMusic->Resume(); if (choice == 3) { Sys_LoadMenu(); // Back to System Menu @@ -1755,7 +1752,7 @@ static int MenuInstall() { int ret, choice = 0; char name[200]; - GuiSound btnSoundOver(button_over_pcm, button_over_pcm_size, SOUND_PCM, Settings.sfxvolume); + GuiSound btnSoundOver(button_over_pcm, button_over_pcm_size, Settings.sfxvolume); char imgPath[100]; @@ -1849,22 +1846,15 @@ static int MenuInstall() { } else { __Menu_GetEntries(); //get the entries again GuiSound * instsuccess = NULL; - s32 thetimeofbg = bgMusic->GetPlayTime(); - bgMusic->Stop(); - instsuccess = new GuiSound(success_ogg, success_ogg_size, SOUND_OGG, Settings.sfxvolume); + bgMusic->Pause(); + instsuccess = new GuiSound(success_ogg, success_ogg_size, Settings.sfxvolume); instsuccess->SetVolume(Settings.sfxvolume); instsuccess->SetLoop(0); instsuccess->Play(); WindowPrompt (tr("Successfully installed:"),name,tr("OK")); instsuccess->Stop(); delete instsuccess; - if (!strcmp("", Settings.oggload_path) || !strcmp("notset", Settings.ogg_path)) { - bgMusic->Play(); - } else { - bgMusic->PlayOggFile(Settings.ogg_path); - } - bgMusic->SetPlayTime(thetimeofbg); - SetVolumeOgg(255*(Settings.volume/100.0)); + bgMusic->Resume(); menu = MENU_DISCLIST; break; } @@ -1933,8 +1923,10 @@ static int MenuFormat() { } } - GuiSound btnSoundOver(button_over_pcm, button_over_pcm_size, SOUND_PCM, Settings.sfxvolume); - GuiSound btnClick(button_click2_pcm, button_click2_pcm_size, SOUND_PCM, Settings.sfxvolume); + GuiSound btnSoundOver(button_over_pcm, button_over_pcm_size, Settings.sfxvolume); + // because destroy GuiSound must wait while sound playing is finished, we use a global sound + if(!btnClick2) btnClick2=new GuiSound(button_click2_pcm, button_click2_pcm_size, Settings.sfxvolume); + // GuiSound btnClick(button_click2_pcm, button_click2_pcm_size, Settings.sfxvolume); snprintf(imgPath, sizeof(imgPath), "%swiimote_poweroff.png", CFG.theme_path); GuiImageData btnpwroff(imgPath, wiimote_poweroff_png); snprintf(imgPath, sizeof(imgPath), "%swiimote_poweroff_over.png", CFG.theme_path); @@ -1958,12 +1950,12 @@ static int MenuFormat() { GuiImage poweroffBtnImgOver(&btnpwroffOver); poweroffBtnImg.SetWidescreen(CFG.widescreen); poweroffBtnImgOver.SetWidescreen(CFG.widescreen); - GuiButton poweroffBtn(&poweroffBtnImg,&poweroffBtnImgOver, 0, 3, THEME.power_x, THEME.power_y, &trigA, &btnSoundOver, &btnClick,1); + GuiButton poweroffBtn(&poweroffBtnImg,&poweroffBtnImgOver, 0, 3, THEME.power_x, THEME.power_y, &trigA, &btnSoundOver, btnClick2,1); GuiImage exitBtnImg(&btnhome); GuiImage exitBtnImgOver(&btnhomeOver); exitBtnImg.SetWidescreen(CFG.widescreen); exitBtnImgOver.SetWidescreen(CFG.widescreen); - GuiButton exitBtn(&exitBtnImg,&exitBtnImgOver, 0, 3, THEME.home_x, THEME.home_y, &trigA, &btnSoundOver, &btnClick,1); + GuiButton exitBtn(&exitBtnImg,&exitBtnImgOver, 0, 3, THEME.home_x, THEME.home_y, &trigA, &btnSoundOver, btnClick2,1); exitBtn.SetTrigger(&trigHome); GuiCustomOptionBrowser optionBrowser(396, 280, &options, CFG.theme_path, "bg_options_settings.png", bg_options_settings_png, 0, 10); @@ -2171,18 +2163,16 @@ int MainMenu(int menu) { ResumeGui(); - bgMusic = new GuiSound(bg_music_ogg, bg_music_ogg_size, SOUND_OGG, Settings.volume); - bgMusic->SetVolume(Settings.volume); + bgMusic = new GuiSound(bg_music_ogg, bg_music_ogg_size, Settings.volume); bgMusic->SetLoop(1); //loop music // startup music - if (!strcmp("", Settings.oggload_path) || !strcmp("notset", Settings.ogg_path)) { - bgMusic->Play(); - } else { - bgMusic->PlayOggFile(Settings.ogg_path); + if (strcmp("", Settings.oggload_path) && strcmp("notset", Settings.ogg_path)) { + bgMusic->Load(Settings.ogg_path); } + bgMusic->Play(); while (currentMenu != MENU_EXIT) { - SetVolumeOgg(255*(Settings.volume/100.0)); + bgMusic->SetVolume(Settings.volume); switch (currentMenu) { case MENU_CHECK: diff --git a/source/menu.h b/source/menu.h index 347b1d43..0ffb3a75 100644 --- a/source/menu.h +++ b/source/menu.h @@ -33,5 +33,6 @@ enum { }; class GuiImageData; GuiImageData *LoadCoverImage(struct discHdr *header, bool Prefere3D=true, bool noCover=true); - +class GuiSound; +extern GuiSound *btnClick2; #endif diff --git a/source/oggplayer.c b/source/oggplayer.c deleted file mode 100644 index 9ffd3f10..00000000 --- a/source/oggplayer.c +++ /dev/null @@ -1,336 +0,0 @@ -/* - Copyright (c) 2008 Francisco Muñoz 'Hermes' - All rights reserved. - - Threading modifications/corrections by Tantric, 2009 - - Redistribution and use in source and binary forms, with or without modification, are - permitted provided that the following conditions are met: - - - Redistributions of source code must retain the above copyright notice, this list of - conditions and the following disclaimer. - - Redistributions in binary form must reproduce the above copyright notice, this list - of conditions and the following disclaimer in the documentation and/or other - materials provided with the distribution. - - The names of the contributors may not be used to endorse or promote products derived - from this software without specific prior written permission. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY - EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL - THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF - THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "oggplayer.h" -#include -#include -#include -#include - -/* OGG control */ - -#define READ_SAMPLES 4096 // samples that it must read before to send -#define MAX_PCMOUT 4096 // minimum size to read ogg samples -typedef struct { - OggVorbis_File vf; - vorbis_info *vi; - int current_section; - - // OGG file operation - int fd; - int mode; - int eof; - int flag; - int volume; - int seek_time; - - /* OGG buffer control */ - short pcmout[2][READ_SAMPLES + MAX_PCMOUT * 2]; /* take 4k out of the data segment, not the stack */ - int pcmout_pos; - int pcm_indx; - -} private_data_ogg; - -static private_data_ogg private_ogg; - -// OGG thread control - -#define STACKSIZE 8192 - -static u8 oggplayer_stack[STACKSIZE]; -static lwpq_t oggplayer_queue = LWP_THREAD_NULL; -static lwp_t h_oggplayer = LWP_THREAD_NULL; -static int ogg_thread_running = 0; - -static void ogg_add_callback(int voice) { - if (!ogg_thread_running) { - ASND_StopVoice(0); - return; - } - - if (private_ogg.flag & 128) - return; // Ogg is paused - - if (private_ogg.pcm_indx >= READ_SAMPLES) { - if (ASND_AddVoice(0, - (void *) private_ogg.pcmout[private_ogg.pcmout_pos], - private_ogg.pcm_indx << 1) == 0) { - private_ogg.pcmout_pos ^= 1; - private_ogg.pcm_indx = 0; - private_ogg.flag = 0; - LWP_ThreadSignal(oggplayer_queue); - } - } else { - if (private_ogg.flag & 64) { - private_ogg.flag &= ~64; - LWP_ThreadSignal(oggplayer_queue); - } - } -} - -static void * ogg_player_thread(private_data_ogg * priv) { - int first_time = 1; - long ret; - - ogg_thread_running = 0; - //init - LWP_InitQueue(&oggplayer_queue); - - priv[0].vi = ov_info(&priv[0].vf, -1); - - ASND_Pause(0); - - priv[0].pcm_indx = 0; - priv[0].pcmout_pos = 0; - priv[0].eof = 0; - priv[0].flag = 0; - priv[0].current_section = 0; - - ogg_thread_running = 1; - - while (!priv[0].eof && ogg_thread_running) { - if (priv[0].flag) - LWP_ThreadSleep(oggplayer_queue); // wait only when i have samples to send - - if (priv[0].flag == 0) { // wait to all samples are sended - if (ASND_TestPointer(0, priv[0].pcmout[priv[0].pcmout_pos]) - && ASND_StatusVoice(0) != SND_UNUSED) { - priv[0].flag |= 64; - continue; - } - if (priv[0].pcm_indx < READ_SAMPLES) { - priv[0].flag = 3; - - if (priv[0].seek_time >= 0) { - ov_time_seek(&priv[0].vf, priv[0].seek_time); - priv[0].seek_time = -1; - } - - ret - = ov_read( - &priv[0].vf, - (void *) &priv[0].pcmout[priv[0].pcmout_pos][priv[0].pcm_indx], - MAX_PCMOUT,/*0,2,1,*/&priv[0].current_section); - priv[0].flag &= 192; - if (ret == 0) { - /* EOF */ - if (priv[0].mode & 1) - ov_time_seek(&priv[0].vf, 0); // repeat - else - priv[0].eof = 1; // stops - // - } else if (ret < 0) { - /* error in the stream. Not a problem, just reporting it in - case we (the app) cares. In this case, we don't. */ - if (ret != OV_HOLE) { - if (priv[0].mode & 1) - ov_time_seek(&priv[0].vf, 0); // repeat - else - priv[0].eof = 1; // stops - } - } else { - /* we don't bother dealing with sample rate changes, etc, but - you'll have to*/ - priv[0].pcm_indx += ret >> 1; //get 16 bits samples - } - } else - priv[0].flag = 1; - } - - if (priv[0].flag == 1) { - if (ASND_StatusVoice(0) == SND_UNUSED || first_time) { - first_time = 0; - if (priv[0].vi->channels == 2) { - ASND_SetVoice(0, VOICE_STEREO_16BIT, priv[0].vi->rate, 0, - (void *) priv[0].pcmout[priv[0].pcmout_pos], - priv[0].pcm_indx << 1, priv[0].volume, - priv[0].volume, ogg_add_callback); - priv[0].pcmout_pos ^= 1; - priv[0].pcm_indx = 0; - priv[0].flag = 0; - } else { - ASND_SetVoice(0, VOICE_MONO_16BIT, priv[0].vi->rate, 0, - (void *) priv[0].pcmout[priv[0].pcmout_pos], - priv[0].pcm_indx << 1, priv[0].volume, - priv[0].volume, ogg_add_callback); - priv[0].pcmout_pos ^= 1; - priv[0].pcm_indx = 0; - priv[0].flag = 0; - } - } - } - usleep(100); - } - ov_clear(&priv[0].vf); - priv[0].fd = -1; - priv[0].pcm_indx = 0; - ogg_thread_running = 0; - - return 0; -} - -void StopOgg() { - ASND_StopVoice(0); - ogg_thread_running = 0; - - if (h_oggplayer != LWP_THREAD_NULL) { - if (oggplayer_queue != LWP_TQUEUE_NULL) - LWP_ThreadSignal(oggplayer_queue); - LWP_JoinThread(h_oggplayer, NULL); - h_oggplayer = LWP_THREAD_NULL; - } - if (oggplayer_queue != LWP_TQUEUE_NULL) { - LWP_CloseQueue(oggplayer_queue); - oggplayer_queue = LWP_TQUEUE_NULL; - } -} - -int PlayOgg(int fd, int time_pos, int mode) { - StopOgg(); - - private_ogg.fd = fd; - private_ogg.mode = mode; - private_ogg.eof = 0; - private_ogg.volume = 127; - private_ogg.flag = 0; - private_ogg.seek_time = -1; - - if (time_pos > 0) - private_ogg.seek_time = time_pos; - - if (fd < 0) { - private_ogg.fd = -1; - return -1; - } - if (ov_open((void *) &private_ogg.fd, &private_ogg.vf, NULL, 0) < 0) { - mem_close(private_ogg.fd); // mem_close() can too close files from devices - private_ogg.fd = -1; - ogg_thread_running = 0; - return -1; - } - - if (LWP_CreateThread(&h_oggplayer, (void *) ogg_player_thread, - &private_ogg, oggplayer_stack, STACKSIZE, 80) == -1) { - ogg_thread_running = 0; - ov_clear(&private_ogg.vf); - private_ogg.fd = -1; - return -1; - } - return 0; -} - - -int PlayOggFromFile(char * path, int loop) { - - StopOgg(); - u32 filesize = 0; - char * bufferogg = NULL; - size_t resultogg; - - FILE * pFile; - pFile = fopen (path, "rb"); - - //Check that pFile exist - if (pFile==NULL) { - return -1; - } - - // get file size: - fseek (pFile , 0 , SEEK_END); - filesize = ftell (pFile); - rewind (pFile); - - // allocate memory to contain the whole file: - bufferogg = (char*) malloc (sizeof(char)*filesize); - if (bufferogg == NULL) { - fputs (" Memory error",stderr); - exit (2); - } - - // copy the file into the buffer: - resultogg = fread (bufferogg,1,filesize,pFile); - if (resultogg != filesize) { - fputs (" Reading error",stderr); - exit (3); - } - - fclose (pFile); - - if (loop) - return PlayOgg(mem_open((char *)bufferogg, filesize), 0, OGG_INFINITE_TIME); - else - return PlayOgg(mem_open((char *)bufferogg, filesize), 0, OGG_ONE_TIME); -} - - -void PauseOgg(int pause) { - if (pause) { - private_ogg.flag |= 128; - } else { - if (private_ogg.flag & 128) { - private_ogg.flag |= 64; - private_ogg.flag &= ~128; - if (ogg_thread_running > 0) { - LWP_ThreadSignal(oggplayer_queue); - } - } - - } -} - -int StatusOgg() { - if (ogg_thread_running == 0) - return -1; // Error - else if (private_ogg.eof) - return 255; // EOF - else if (private_ogg.flag & 128) - return 2; // paused - else - return 1; // running -} - -void SetVolumeOgg(int volume) { - private_ogg.volume = volume; - ASND_ChangeVolumeVoice(0, volume, volume); -} - -s32 GetTimeOgg() { - int ret; - if (ogg_thread_running == 0 || private_ogg.fd < 0) - return 0; - ret = ((s32) ov_time_tell(&private_ogg.vf)); - if (ret < 0) - ret = 0; - - return ret; -} - -void SetTimeOgg(s32 time_pos) { - if (time_pos >= 0) - private_ogg.seek_time = time_pos; -} diff --git a/source/oggplayer.h b/source/oggplayer.h deleted file mode 100644 index d6649632..00000000 --- a/source/oggplayer.h +++ /dev/null @@ -1,175 +0,0 @@ -/* - Copyright (c) 2008 Francisco Muñoz 'Hermes' - All rights reserved. - - Redistribution and use in source and binary forms, with or without modification, are - permitted provided that the following conditions are met: - - - Redistributions of source code must retain the above copyright notice, this list of - conditions and the following disclaimer. - - Redistributions in binary form must reproduce the above copyright notice, this list - of conditions and the following disclaimer in the documentation and/or other - materials provided with the distribution. - - The names of the contributors may not be used to endorse or promote products derived - from this software without specific prior written permission. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY - EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL - THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF - THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef __OGGPLAYER_H__ -#define __OGGPLAYER_H__ - -#include -#include "tremor/ivorbiscodec.h" -#include "tremor/ivorbisfile.h" - -#ifdef __cplusplus -extern "C" { -#endif - -#define OGG_ONE_TIME 0 -#define OGG_INFINITE_TIME 1 - -#define OGG_STATUS_RUNNING 1 -#define OGG_STATUS_ERR -1 -#define OGG_STATUS_PAUSED 2 -#define OGG_STATUS_EOF 255 - - /*------------------------------------------------------------------------------------------------------------------------------------------------------*/ - /* Player OGG functions */ - /*------------------------------------------------------------------------------------------------------------------------------------------------------*/ - - /* int PlayOgg(int fd, int time_pos, int mode); - - Play an Ogg file. This file can be loaded from memory (mem_open(void *ogg, int size_ogg)) or from device with open("device:file.ogg",O_RDONLY,0); - - NOTE: The file is closed by the player when you call PlayOgg(), StopOgg() or if it fail. - - -- Params --- - - fd: file descriptor from open() or mem_open() - - time_pos: initial time position in the file (in milliseconds). For example, use 30000 to advance 30 seconds - - mode: Use OGG_ONE_TIME or OGG_INFINITE_TIME. When you use OGG_ONE_TIME the sound stops and StatusOgg() return OGG_STATUS_EOF - - return: 0- Ok, -1 Error - - */ - - int PlayOgg(int fd, int time_pos, int mode); - - /*------------------------------------------------------------------------------------------------------------------------------------------------------*/ - /* int PlayOgg(char * path, int loop); - Just give the function the full device+path to OGG to play it - loop = 1 for Loop and 0 for one time playing - */ - int PlayOggFromFile(char * path, int loop); - /*------------------------------------------------------------------------------------------------------------------------------------------------------*/ - - /* void StopOgg(); - - Stop an Ogg file. - - NOTE: The file is closed and the player thread is released - - -- Params --- - - - */ - - void StopOgg(); - - /*------------------------------------------------------------------------------------------------------------------------------------------------------*/ - - /* void PauseOgg(int pause); - - Pause an Ogg file. - - -- Params --- - - pause: 0 -> continue, 1-> pause - - */ - - void PauseOgg(int pause); - - /*------------------------------------------------------------------------------------------------------------------------------------------------------*/ - - /* int StatusOgg(); - - Return the Ogg status - - -- Params --- - - - return: OGG_STATUS_RUNNING - OGG_STATUS_ERR -> not initialized? - OGG_STATUS_PAUSED - OGG_STATUS_EOF -> player stopped by End Of File - - */ - - int StatusOgg(); - - /*------------------------------------------------------------------------------------------------------------------------------------------------------*/ - - /* void SetVolumeOgg(int volume); - - Set the Ogg playing volume. - NOTE: it change the volume of voice 0 (used for the Ogg player) - - -- Params --- - - volume: 0 to 255 (max) - - */ - - void SetVolumeOgg(int volume); - - /*------------------------------------------------------------------------------------------------------------------------------------------------------*/ - - /* s32 GetTimeOgg(); - - Return the Ogg time from the starts of the file - - -- Params --- - - return: 0 -> Ok or error condition (you must ignore this value) - >0 -> time in milliseconds from the starts - - */ - - s32 GetTimeOgg(); - - /*------------------------------------------------------------------------------------------------------------------------------------------------------*/ - - /* void SetTimeOgg(s32 time_pos); - - Set the time position - - NOTE: The file is closed by the player when you call PlayOgg(), StopOgg() or if it fail. - - -- Params --- - - time_pos: time position in the file (in milliseconds). For example, use 30000 to advance 30 seconds - - */ - - void SetTimeOgg(s32 time_pos); - - /*------------------------------------------------------------------------------------------------------------------------------------------------------*/ - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/source/prompts/DiscBrowser.cpp b/source/prompts/DiscBrowser.cpp index ba11a608..d05efae6 100644 --- a/source/prompts/DiscBrowser.cpp +++ b/source/prompts/DiscBrowser.cpp @@ -141,8 +141,10 @@ int DiscBrowse(struct discHdr * header) { return -1; } - GuiSound btnSoundOver(button_over_pcm, button_over_pcm_size, SOUND_PCM, Settings.sfxvolume); - GuiSound btnClick(button_click2_pcm, button_click2_pcm_size, SOUND_PCM, Settings.sfxvolume); + GuiSound btnSoundOver(button_over_pcm, button_over_pcm_size, Settings.sfxvolume); + // because destroy GuiSound must wait while sound playing is finished, we use a global sound + if(!btnClick2) btnClick2=new GuiSound(button_click2_pcm, button_click2_pcm_size, Settings.sfxvolume); + // GuiSound btnClick(button_click2_pcm, button_click2_pcm_size, Settings.sfxvolume); char imgPath[100]; @@ -176,7 +178,7 @@ int DiscBrowse(struct discHdr * header) { cancelBtnTxt.SetWidescreen(CFG.widescreen); cancelBtnImg.SetWidescreen(CFG.widescreen); } - GuiButton cancelBtn(&cancelBtnImg,&cancelBtnImg, 2, 3, 180, 400, &trigA, &btnSoundOver, &btnClick,1); + GuiButton cancelBtn(&cancelBtnImg,&cancelBtnImg, 2, 3, 180, 400, &trigA, &btnSoundOver, btnClick2,1); cancelBtn.SetScale(0.9); cancelBtn.SetLabel(&cancelBtnTxt); cancelBtn.SetTrigger(&trigB); diff --git a/source/prompts/PromptWindows.cpp b/source/prompts/PromptWindows.cpp index e941346b..12393c43 100644 --- a/source/prompts/PromptWindows.cpp +++ b/source/prompts/PromptWindows.cpp @@ -33,11 +33,11 @@ #include "svnrev.h" #include "audio.h" #include "xml/xml.h" -#include "../wad/title.h" +#include "wad/title.h" #include "language/UpdateLanguage.h" #include "gecko.h" -#include "../lstub.h" -#include "Game_Sound.h" +#include "lstub.h" +#include "bannersound.h" @@ -84,8 +84,10 @@ int OnScreenKeyboard(char * var, u32 maxlen, int min) { GuiKeyboard keyboard(var, maxlen, min, keyset); - GuiSound btnSoundOver(button_over_pcm, button_over_pcm_size, SOUND_PCM, Settings.sfxvolume); - GuiSound btnClick(button_click2_pcm, button_click2_pcm_size, SOUND_PCM, Settings.sfxvolume); + GuiSound btnSoundOver(button_over_pcm, button_over_pcm_size, Settings.sfxvolume); + // because destroy GuiSound must wait while sound playing is finished, we use a global sound + if(!btnClick2) btnClick2=new GuiSound(button_click2_pcm, button_click2_pcm_size,Settings.sfxvolume); + // GuiSound btnClick(button_click2_pcm, button_click2_pcm_size, Settings.sfxvolume); char imgPath[100]; snprintf(imgPath, sizeof(imgPath), "%sbutton_dialogue_box.png", CFG.theme_path); @@ -102,7 +104,7 @@ int OnScreenKeyboard(char * var, u32 maxlen, int min) { okBtnTxt.SetWidescreen(CFG.widescreen); okBtnImg.SetWidescreen(CFG.widescreen); } - GuiButton okBtn(&okBtnImg,&okBtnImg, 0, 4, 5, 15, &trigA, &btnSoundOver, &btnClick,1); + GuiButton okBtn(&okBtnImg,&okBtnImg, 0, 4, 5, 15, &trigA, &btnSoundOver, btnClick2,1); okBtn.SetLabel(&okBtnTxt); GuiText cancelBtnTxt(tr("Cancel"), 22, THEME.prompttext); GuiImage cancelBtnImg(&btnOutline); @@ -110,7 +112,7 @@ int OnScreenKeyboard(char * var, u32 maxlen, int min) { cancelBtnTxt.SetWidescreen(CFG.widescreen); cancelBtnImg.SetWidescreen(CFG.widescreen); } - GuiButton cancelBtn(&cancelBtnImg,&cancelBtnImg, 1, 4, -5, 15, &trigA, &btnSoundOver, &btnClick,1); + GuiButton cancelBtn(&cancelBtnImg,&cancelBtnImg, 1, 4, -5, 15, &trigA, &btnSoundOver, btnClick2,1); cancelBtn.SetLabel(&cancelBtnTxt); cancelBtn.SetTrigger(&trigB); @@ -154,10 +156,9 @@ void WindowCredits() { int angle = 0; GuiSound * creditsMusic = NULL; - s32 thetimeofbg = bgMusic->GetPlayTime(); - StopOgg(); + bgMusic->Pause(); - creditsMusic = new GuiSound(credits_music_ogg, credits_music_ogg_size, SOUND_OGG, 55); + creditsMusic = new GuiSound(credits_music_ogg, credits_music_ogg_size, 55); creditsMusic->SetVolume(60); creditsMusic->SetLoop(1); creditsMusic->Play(); @@ -366,13 +367,7 @@ void WindowCredits() { } ResumeGui(); - if (!strcmp("", Settings.oggload_path) || !strcmp("notset", Settings.ogg_path)) { - bgMusic->Play(); - } else { - bgMusic->PlayOggFile(Settings.ogg_path); - } - bgMusic->SetPlayTime(thetimeofbg); - SetVolumeOgg(255*(Settings.volume/100.0)); + bgMusic->Resume(); } /**************************************************************************** @@ -450,8 +445,10 @@ int WindowPrompt(const char *title, const char *msg, const char *btn1Label, promptWindow.SetAlignment(ALIGN_CENTRE, ALIGN_MIDDLE); promptWindow.SetPosition(0, -10); - GuiSound btnSoundOver(button_over_pcm, button_over_pcm_size, SOUND_PCM, Settings.sfxvolume); - GuiSound btnClick(button_click2_pcm, button_click2_pcm_size, SOUND_PCM, Settings.sfxvolume); + GuiSound btnSoundOver(button_over_pcm, button_over_pcm_size, Settings.sfxvolume); + // because destroy GuiSound must wait while sound playing is finished, we use a global sound + if(!btnClick2) btnClick2=new GuiSound(button_click2_pcm, button_click2_pcm_size, Settings.sfxvolume); + // GuiSound btnClick(button_click2_pcm, button_click2_pcm_size, Settings.sfxvolume); char imgPath[100]; snprintf(imgPath, sizeof(imgPath), "%sbutton_dialogue_box.png", CFG.theme_path); GuiImageData btnOutline(imgPath, button_dialogue_box_png); @@ -484,7 +481,7 @@ int WindowPrompt(const char *title, const char *msg, const char *btn1Label, btn1Img.SetWidescreen(CFG.widescreen); } - GuiButton btn1(&btn1Img, &btn1Img, 0,3,0,0,&trigA,&btnSoundOver,&btnClick,1); + GuiButton btn1(&btn1Img, &btn1Img, 0,3,0,0,&trigA,&btnSoundOver,btnClick2,1); btn1.SetLabel(&btn1Txt); btn1.SetState(STATE_SELECTED); @@ -494,7 +491,7 @@ int WindowPrompt(const char *title, const char *msg, const char *btn1Label, btn2Txt.SetWidescreen(CFG.widescreen); btn2Img.SetWidescreen(CFG.widescreen); } - GuiButton btn2(&btn2Img, &btn2Img, 0,3,0,0,&trigA,&btnSoundOver,&btnClick,1); + GuiButton btn2(&btn2Img, &btn2Img, 0,3,0,0,&trigA,&btnSoundOver,btnClick2,1); btn2.SetLabel(&btn2Txt); if (!btn3Label && !btn4Label) btn2.SetTrigger(&trigB); @@ -505,7 +502,7 @@ int WindowPrompt(const char *title, const char *msg, const char *btn1Label, btn3Txt.SetWidescreen(CFG.widescreen); btn3Img.SetWidescreen(CFG.widescreen); } - GuiButton btn3(&btn3Img, &btn3Img, 0,3,0,0,&trigA,&btnSoundOver,&btnClick,1); + GuiButton btn3(&btn3Img, &btn3Img, 0,3,0,0,&trigA,&btnSoundOver,btnClick2,1); btn3.SetLabel(&btn3Txt); if (!btn4Label) btn3.SetTrigger(&trigB); @@ -516,7 +513,7 @@ int WindowPrompt(const char *title, const char *msg, const char *btn1Label, btn4Txt.SetWidescreen(CFG.widescreen); btn4Img.SetWidescreen(CFG.widescreen); } - GuiButton btn4(&btn4Img, &btn4Img, 0,3,0,0,&trigA,&btnSoundOver,&btnClick,1); + GuiButton btn4(&btn4Img, &btn4Img, 0,3,0,0,&trigA,&btnSoundOver,btnClick2,1); btn4.SetLabel(&btn4Txt); if (btn4Label) btn4.SetTrigger(&trigB); @@ -696,13 +693,13 @@ WindowExitPrompt(const char *title, const char *msg, const char *btn1Label, gprintf("\nWindowExitPrompt()"); GuiSound * homein = NULL; - homein = new GuiSound(menuin_ogg, menuin_ogg_size, SOUND_OGG, Settings.sfxvolume); + homein = new GuiSound(menuin_ogg, menuin_ogg_size, Settings.sfxvolume); homein->SetVolume(Settings.sfxvolume); homein->SetLoop(0); homein->Play(); GuiSound * homeout = NULL; - homeout = new GuiSound(menuout_ogg, menuout_ogg_size, SOUND_OGG, Settings.sfxvolume); + homeout = new GuiSound(menuout_ogg, menuout_ogg_size, Settings.sfxvolume); homeout->SetVolume(Settings.sfxvolume); homeout->SetLoop(0); @@ -717,8 +714,10 @@ WindowExitPrompt(const char *title, const char *msg, const char *btn1Label, GuiWindow promptWindow(640,480); promptWindow.SetAlignment(ALIGN_LEFT, ALIGN_TOP); promptWindow.SetPosition(0, 0); - GuiSound btnSoundOver(button_over_pcm, button_over_pcm_size, SOUND_PCM, Settings.sfxvolume); - GuiSound btnClick(button_click2_pcm, button_click2_pcm_size, SOUND_PCM, Settings.sfxvolume); + GuiSound btnSoundOver(button_over_pcm, button_over_pcm_size, Settings.sfxvolume); + // because destroy GuiSound must wait while sound playing is finished, we use a global sound + if(!btnClick2) btnClick2=new GuiSound(button_click2_pcm, button_click2_pcm_size, Settings.sfxvolume); + // GuiSound btnClick(button_click2_pcm, button_click2_pcm_size, Settings.sfxvolume); GuiImageData top(exit_top_png); GuiImageData topOver(exit_top_over_png); @@ -810,7 +809,7 @@ WindowExitPrompt(const char *title, const char *msg, const char *btn1Label, GuiImage btn1Img(&top); GuiImage btn1OverImg(&topOver); - GuiButton btn1(&btn1Img,&btn1OverImg, 0, 3, 0, 0, &trigA, &btnSoundOver, &btnClick,0); + GuiButton btn1(&btn1Img,&btn1OverImg, 0, 3, 0, 0, &trigA, &btnSoundOver, btnClick2,0); btn1.SetEffect(EFFECT_SLIDE_TOP | EFFECT_SLIDE_IN, 50); GuiText btn2Txt(btn1Label, 28, (GXColor) {0, 0, 0, 255}); @@ -819,7 +818,7 @@ WindowExitPrompt(const char *title, const char *msg, const char *btn1Label, btn2Txt.SetWidescreen(CFG.widescreen); btn2Img.SetWidescreen(CFG.widescreen); } - GuiButton btn2(&btn2Img,&btn2Img, 2, 5, -150, 0, &trigA, &btnSoundOver, &btnClick,1); + GuiButton btn2(&btn2Img,&btn2Img, 2, 5, -150, 0, &trigA, &btnSoundOver, btnClick2,1); btn2.SetLabel(&btn2Txt); btn2.SetEffect(EFFECT_SLIDE_LEFT | EFFECT_SLIDE_IN, 50); btn2.SetRumble(false); @@ -832,7 +831,7 @@ WindowExitPrompt(const char *title, const char *msg, const char *btn1Label, btn3Txt.SetWidescreen(CFG.widescreen); btn3Img.SetWidescreen(CFG.widescreen); } - GuiButton btn3(&btn3Img,&btn3Img, 2, 5, 150, 0, &trigA, &btnSoundOver, &btnClick,1); + GuiButton btn3(&btn3Img,&btn3Img, 2, 5, 150, 0, &trigA, &btnSoundOver, btnClick2,1); btn3.SetLabel(&btn3Txt); btn3.SetEffect(EFFECT_SLIDE_RIGHT | EFFECT_SLIDE_IN, 50); btn3.SetRumble(false); @@ -840,7 +839,7 @@ WindowExitPrompt(const char *title, const char *msg, const char *btn1Label, GuiImage btn4Img(&bottom); GuiImage btn4OverImg(&bottomOver); - GuiButton btn4(&btn4Img,&btn4OverImg, 0, 4, 0, 0, &trigA, &btnSoundOver, &btnClick,0); + GuiButton btn4(&btn4Img,&btn4OverImg, 0, 4, 0, 0, &trigA, &btnSoundOver, btnClick2,0); btn4.SetTrigger(&trigB); btn4.SetTrigger(&trigHome); btn4.SetEffect(EFFECT_SLIDE_BOTTOM | EFFECT_SLIDE_IN, 50); @@ -1025,14 +1024,16 @@ int GameWindowPrompt() { char ID[5]; char IDFull[7]; - GameSound * gameSound = NULL; + GuiSound * gameSound = NULL; gprintf("\nGameWindowPrompt()"); GuiWindow promptWindow(472,320); promptWindow.SetAlignment(ALIGN_CENTRE, ALIGN_MIDDLE); promptWindow.SetPosition(0, -10); - GuiSound btnSoundOver(button_over_pcm, button_over_pcm_size, SOUND_PCM, Settings.sfxvolume); - GuiSound btnClick(button_click2_pcm, button_click2_pcm_size, SOUND_PCM, Settings.sfxvolume); + GuiSound btnSoundOver(button_over_pcm, button_over_pcm_size, Settings.sfxvolume); + // because destroy GuiSound must wait while sound playing is finished, we use a global sound + if(!btnClick2) btnClick2=new GuiSound(button_click2_pcm, button_click2_pcm_size, Settings.sfxvolume); + // GuiSound btnClick(button_click2_pcm, button_click2_pcm_size, Settings.sfxvolume); char imgPath[100]; snprintf(imgPath, sizeof(imgPath), "%sbutton_dialogue_box.png", CFG.theme_path); @@ -1082,7 +1083,7 @@ int GameWindowPrompt() { nameBtn.SetAlignment(ALIGN_CENTRE, ALIGN_MIDDLE); nameBtn.SetPosition(0,-122); nameBtn.SetSoundOver(&btnSoundOver); - nameBtn.SetSoundClick(&btnClick); + nameBtn.SetSoundClick(btnClick2); if (!mountMethod) nameBtn.SetToolTip(&nameBtnTT,24,-30, ALIGN_LEFT); if (Settings.godmode == 1 && !mountMethod) { @@ -1116,7 +1117,7 @@ int GameWindowPrompt() { btn1.SetImage(&diskImg); btn1.SetSoundOver(&btnSoundOver); - btn1.SetSoundClick(&btnClick); + btn1.SetSoundClick(btnClick2); btn1.SetTrigger(&trigA); btn1.SetState(STATE_SELECTED); @@ -1126,7 +1127,7 @@ int GameWindowPrompt() { btn2Txt.SetWidescreen(CFG.widescreen); btn2Img.SetWidescreen(CFG.widescreen); } - GuiButton btn2(&btn2Img,&btn2Img, 1, 5, 0, 0, &trigA, &btnSoundOver, &btnClick,1); + GuiButton btn2(&btn2Img,&btn2Img, 1, 5, 0, 0, &trigA, &btnSoundOver, btnClick2,1); if (Settings.godmode == 1 && mountMethod!=2 && mountMethod!=3) { btn2.SetAlignment(ALIGN_RIGHT, ALIGN_BOTTOM); btn2.SetPosition(-50, -40); @@ -1144,7 +1145,7 @@ int GameWindowPrompt() { btn3Txt.SetWidescreen(CFG.widescreen); btn3Img.SetWidescreen(CFG.widescreen); } - GuiButton btn3(&btn3Img,&btn3Img, 0, 4, 50, -40, &trigA, &btnSoundOver, &btnClick,1); + GuiButton btn3(&btn3Img,&btn3Img, 0, 4, 50, -40, &trigA, &btnSoundOver, btnClick2,1); btn3.SetLabel(&btn3Txt); GuiImage btnFavoriteImg1; @@ -1165,17 +1166,17 @@ int GameWindowPrompt() { GuiButton btnFavorite4(imgFavorite.GetWidth(), imgFavorite.GetHeight()); GuiButton btnFavorite5(imgFavorite.GetWidth(), imgFavorite.GetHeight()); - SetupFavoriteButton(&btnFavorite1, -198, &btnFavoriteImg1, &btnSoundOver, &btnClick, &trigA); - SetupFavoriteButton(&btnFavorite2, -171, &btnFavoriteImg2, &btnSoundOver, &btnClick, &trigA); - SetupFavoriteButton(&btnFavorite3, -144, &btnFavoriteImg3, &btnSoundOver, &btnClick, &trigA); - SetupFavoriteButton(&btnFavorite4, -117, &btnFavoriteImg4, &btnSoundOver, &btnClick, &trigA); - SetupFavoriteButton(&btnFavorite5, -90, &btnFavoriteImg5, &btnSoundOver, &btnClick, &trigA); + SetupFavoriteButton(&btnFavorite1, -198, &btnFavoriteImg1, &btnSoundOver, btnClick2, &trigA); + SetupFavoriteButton(&btnFavorite2, -171, &btnFavoriteImg2, &btnSoundOver, btnClick2, &trigA); + SetupFavoriteButton(&btnFavorite3, -144, &btnFavoriteImg3, &btnSoundOver, btnClick2, &trigA); + SetupFavoriteButton(&btnFavorite4, -117, &btnFavoriteImg4, &btnSoundOver, btnClick2, &trigA); + SetupFavoriteButton(&btnFavorite5, -90, &btnFavoriteImg5, &btnSoundOver, btnClick2, &trigA); GuiImage btnLeftImg(&imgLeft); if (Settings.wsprompt == yes) { btnLeftImg.SetWidescreen(CFG.widescreen); } - GuiButton btnLeft(&btnLeftImg,&btnLeftImg, 0, 5, 20, 0, &trigA, &btnSoundOver, &btnClick,1); + GuiButton btnLeft(&btnLeftImg,&btnLeftImg, 0, 5, 20, 0, &trigA, &btnSoundOver, btnClick2,1); btnLeft.SetTrigger(&trigL); btnLeft.SetTrigger(&trigMinus); @@ -1183,7 +1184,7 @@ int GameWindowPrompt() { if (Settings.wsprompt == yes) { btnRightImg.SetWidescreen(CFG.widescreen); } - GuiButton btnRight(&btnRightImg,&btnRightImg, 1, 5, -20, 0, &trigA, &btnSoundOver, &btnClick,1); + GuiButton btnRight(&btnRightImg,&btnRightImg, 1, 5, -20, 0, &trigA, &btnSoundOver, btnClick2,1); btnRight.SetTrigger(&trigR); btnRight.SetTrigger(&trigPlus); @@ -1233,19 +1234,22 @@ int GameWindowPrompt() { //load disc image based or what game is seleted struct discHdr * header = (mountMethod==1||mountMethod==2?dvdheader:&gameList[gameSelected]); - if(Settings.gamesound) { if(gameSound) - { - delete gameSound; - gameSound = NULL; - } - - gameSound = new GameSound(header->id); - bgMusic->SetVolume(0); - gameSound->SetVolume(Settings.gamesoundvolume); - gameSound->Play(); + { + gameSound->Stop(); + delete gameSound; + gameSound = NULL; + } + u32 gameSoundDataLen; + const u8 *gameSoundData = LoadBannerSound(header->id, &gameSoundDataLen); + if(gameSoundData) + { + gameSound = new GuiSound(gameSoundData, gameSoundDataLen, Settings.gamesoundvolume, false, true); + bgMusic->SetVolume(0); + gameSound->Play(); + } } snprintf (ID,sizeof(ID),"%c%c%c", header->id[0], header->id[1], header->id[2]); snprintf (IDFull,sizeof(IDFull),"%c%c%c%c%c%c", header->id[0], header->id[1], header->id[2],header->id[3], header->id[4], header->id[5]); @@ -1455,7 +1459,7 @@ int GameWindowPrompt() { else if ((btnRight.GetState() == STATE_CLICKED) && (Settings.xflip == no)) {//next game promptWindow.SetEffect(EFFECT_SLIDE_RIGHT | EFFECT_SLIDE_OUT, 50); changed = 1; - btnClick.Play(); + btnClick2->Play(); gameSelected = (gameSelected + 1) % gameCnt; btnRight.ResetState(); break; @@ -1464,7 +1468,7 @@ int GameWindowPrompt() { else if ((btnLeft.GetState() == STATE_CLICKED) && (Settings.xflip == no)) {//previous game promptWindow.SetEffect(EFFECT_SLIDE_LEFT | EFFECT_SLIDE_OUT, 50); changed = 2; - btnClick.Play(); + btnClick2->Play(); gameSelected = (gameSelected - 1 + gameCnt) % gameCnt; btnLeft.ResetState(); break; @@ -1473,7 +1477,7 @@ int GameWindowPrompt() { else if ((btnRight.GetState() == STATE_CLICKED) && (Settings.xflip == yes)) {//previous game promptWindow.SetEffect(EFFECT_SLIDE_LEFT | EFFECT_SLIDE_OUT, 50); changed = 2; - btnClick.Play(); + btnClick2->Play(); gameSelected = (gameSelected - 1 + gameCnt) % gameCnt; btnRight.ResetState(); break; @@ -1482,7 +1486,7 @@ int GameWindowPrompt() { else if ((btnLeft.GetState() == STATE_CLICKED) && (Settings.xflip == yes)) {//next game promptWindow.SetEffect(EFFECT_SLIDE_RIGHT | EFFECT_SLIDE_OUT, 50); changed = 1; - btnClick.Play(); + btnClick2->Play(); gameSelected = (gameSelected + 1) % gameCnt; btnLeft.ResetState(); break; @@ -1491,7 +1495,7 @@ int GameWindowPrompt() { else if ((btnRight.GetState() == STATE_CLICKED) && (Settings.xflip == sysmenu)) {//previous game promptWindow.SetEffect(EFFECT_SLIDE_LEFT | EFFECT_SLIDE_OUT, 50); changed = 2; - btnClick.Play(); + btnClick2->Play(); gameSelected = (gameSelected + 1) % gameCnt; btnRight.ResetState(); break; @@ -1500,7 +1504,7 @@ int GameWindowPrompt() { else if ((btnLeft.GetState() == STATE_CLICKED) && (Settings.xflip == sysmenu)) {//next game promptWindow.SetEffect(EFFECT_SLIDE_RIGHT | EFFECT_SLIDE_OUT, 50); changed = 1; - btnClick.Play(); + btnClick2->Play(); gameSelected = (gameSelected - 1 + gameCnt) % gameCnt; btnLeft.ResetState(); break; @@ -1509,7 +1513,7 @@ int GameWindowPrompt() { else if ((btnRight.GetState() == STATE_CLICKED) && (Settings.xflip == wtf)) {//previous game promptWindow.SetEffect(EFFECT_SLIDE_RIGHT | EFFECT_SLIDE_OUT, 50); changed = 1; - btnClick.Play(); + btnClick2->Play(); gameSelected = (gameSelected - 1 + gameCnt) % gameCnt; btnRight.ResetState(); break; @@ -1518,7 +1522,7 @@ int GameWindowPrompt() { else if ((btnLeft.GetState() == STATE_CLICKED) && (Settings.xflip == wtf)) {//next game promptWindow.SetEffect(EFFECT_SLIDE_LEFT | EFFECT_SLIDE_OUT, 50); changed = 2; - btnClick.Play(); + btnClick2->Play(); gameSelected = (gameSelected + 1) % gameCnt; btnLeft.ResetState(); break; @@ -1527,7 +1531,7 @@ int GameWindowPrompt() { else if ((btnRight.GetState() == STATE_CLICKED) && (Settings.xflip == disk3d)) {//next game // diskImg.SetBetaRotateEffect(45, 90); changed = 3; - btnClick.Play(); + btnClick2->Play(); gameSelected = (gameSelected + 1) % gameCnt; btnRight.ResetState(); break; @@ -1537,7 +1541,7 @@ int GameWindowPrompt() { // diskImg.SetBetaRotateEffect(-45, 90); // promptWindow.SetEffect(EFFECT_SLIDE_LEFT | EFFECT_SLIDE_OUT, 1/*50*/); changed = 4; - btnClick.Play(); + btnClick2->Play(); gameSelected = (gameSelected - 1 + gameCnt) % gameCnt; btnLeft.ResetState(); break; @@ -1557,7 +1561,8 @@ int GameWindowPrompt() { if(gameSound) { - delete gameSound; + gameSound->Stop(); + delete gameSound; gameSound = NULL; } bgMusic->SetVolume(Settings.volume); @@ -1577,8 +1582,10 @@ DiscWait(const char *title, const char *msg, const char *btn1Label, const char * GuiWindow promptWindow(472,320); promptWindow.SetAlignment(ALIGN_CENTRE, ALIGN_MIDDLE); promptWindow.SetPosition(0, -10); - GuiSound btnSoundOver(button_over_pcm, button_over_pcm_size, SOUND_PCM, Settings.sfxvolume); - GuiSound btnClick(button_click2_pcm, button_click2_pcm_size, SOUND_PCM, Settings.sfxvolume); + GuiSound btnSoundOver(button_over_pcm, button_over_pcm_size, Settings.sfxvolume); + // because destroy GuiSound must wait while sound playing is finished, we use a global sound + if(!btnClick2) btnClick2=new GuiSound(button_click2_pcm, button_click2_pcm_size, Settings.sfxvolume); + // GuiSound btnClick(button_click2_pcm, button_click2_pcm_size, Settings.sfxvolume); char imgPath[100]; snprintf(imgPath, sizeof(imgPath), "%sbutton_dialogue_box.png", CFG.theme_path); @@ -1609,7 +1616,7 @@ DiscWait(const char *title, const char *msg, const char *btn1Label, const char * btn1Txt.SetWidescreen(CFG.widescreen); btn1Img.SetWidescreen(CFG.widescreen); } - GuiButton btn1(&btn1Img,&btn1Img, 1, 5, 0, 0, &trigA, &btnSoundOver, &btnClick,1); + GuiButton btn1(&btn1Img,&btn1Img, 1, 5, 0, 0, &trigA, &btnSoundOver, btnClick2,1); if (btn2Label) { btn1.SetAlignment(ALIGN_LEFT, ALIGN_BOTTOM); @@ -1629,7 +1636,7 @@ DiscWait(const char *title, const char *msg, const char *btn1Label, const char * btn2Txt.SetWidescreen(CFG.widescreen); btn2Img.SetWidescreen(CFG.widescreen); } - GuiButton btn2(&btn2Img,&btn2Img, 1, 4, -20, -25, &trigA, &btnSoundOver, &btnClick,1); + GuiButton btn2(&btn2Img,&btn2Img, 1, 4, -20, -25, &trigA, &btnSoundOver, btnClick2,1); btn2.SetLabel(&btn2Txt); if ((Settings.wsprompt == yes) && (CFG.widescreen)) {/////////////adjust buttons for widescreen @@ -1771,8 +1778,10 @@ bool SearchMissingImages(int choice2) { promptWindow.SetAlignment(ALIGN_CENTRE, ALIGN_MIDDLE); promptWindow.SetPosition(0, -10); - GuiSound btnSoundOver(button_over_pcm, button_over_pcm_size, SOUND_PCM, Settings.sfxvolume); - GuiSound btnClick(button_click2_pcm, button_click2_pcm_size, SOUND_PCM, Settings.sfxvolume); + GuiSound btnSoundOver(button_over_pcm, button_over_pcm_size, Settings.sfxvolume); + // because destroy GuiSound must wait while sound playing is finished, we use a global sound + if(!btnClick2) btnClick2=new GuiSound(button_click2_pcm, button_click2_pcm_size, Settings.sfxvolume); + // GuiSound btnClick(button_click2_pcm, button_click2_pcm_size, Settings.sfxvolume); char imgPath[100]; snprintf(imgPath, sizeof(imgPath), "%sbutton_dialogue_box.png", CFG.theme_path); @@ -1890,8 +1899,10 @@ bool NetworkInitPrompt() { promptWindow.SetAlignment(ALIGN_CENTRE, ALIGN_MIDDLE); promptWindow.SetPosition(0, -10); - GuiSound btnSoundOver(button_over_pcm, button_over_pcm_size, SOUND_PCM, Settings.sfxvolume); - GuiSound btnClick(button_click2_pcm, button_click2_pcm_size, SOUND_PCM, Settings.sfxvolume); + GuiSound btnSoundOver(button_over_pcm, button_over_pcm_size, Settings.sfxvolume); + // because destroy GuiSound must wait while sound playing is finished, we use a global sound + if(!btnClick2) btnClick2=new GuiSound(button_click2_pcm, button_click2_pcm_size, Settings.sfxvolume); + // GuiSound btnClick(button_click2_pcm, button_click2_pcm_size, Settings.sfxvolume); char imgPath[100]; snprintf(imgPath, sizeof(imgPath), "%sbutton_dialogue_box.png", CFG.theme_path); @@ -1922,7 +1933,7 @@ bool NetworkInitPrompt() { btn1Txt.SetWidescreen(CFG.widescreen); btn1Img.SetWidescreen(CFG.widescreen); } - GuiButton btn1(&btn1Img,&btn1Img, 2, 4, 0, -45, &trigA, &btnSoundOver, &btnClick,1); + GuiButton btn1(&btn1Img,&btn1Img, 2, 4, 0, -45, &trigA, &btnSoundOver, btnClick2,1); btn1.SetLabel(&btn1Txt); btn1.SetState(STATE_SELECTED); @@ -1990,8 +2001,10 @@ ProgressDownloadWindow(int choice2) { promptWindow.SetAlignment(ALIGN_CENTRE, ALIGN_MIDDLE); promptWindow.SetPosition(0, -10); - GuiSound btnSoundOver(button_over_pcm, button_over_pcm_size, SOUND_PCM, Settings.sfxvolume); - GuiSound btnClick(button_click2_pcm, button_click2_pcm_size, SOUND_PCM, Settings.sfxvolume); + GuiSound btnSoundOver(button_over_pcm, button_over_pcm_size, Settings.sfxvolume); + // because destroy GuiSound must wait while sound playing is finished, we use a global sound + if(!btnClick2) btnClick2=new GuiSound(button_click2_pcm, button_click2_pcm_size, Settings.sfxvolume); + // GuiSound btnClick(button_click2_pcm, button_click2_pcm_size, Settings.sfxvolume); char imgPath[100]; snprintf(imgPath, sizeof(imgPath), "%sbutton_dialogue_box.png", CFG.theme_path); @@ -2050,7 +2063,7 @@ ProgressDownloadWindow(int choice2) { btn1Txt.SetWidescreen(CFG.widescreen); btn1Img.SetWidescreen(CFG.widescreen); } - GuiButton btn1(&btn1Img,&btn1Img, 2, 4, 0, -45, &trigA, &btnSoundOver, &btnClick,1); + GuiButton btn1(&btn1Img,&btn1Img, 2, 4, 0, -45, &trigA, &btnSoundOver, btnClick2,1); btn1.SetLabel(&btn1Txt); btn1.SetState(STATE_SELECTED); @@ -2472,8 +2485,10 @@ int ProgressUpdateWindow() { promptWindow.SetAlignment(ALIGN_CENTRE, ALIGN_MIDDLE); promptWindow.SetPosition(0, -10); - GuiSound btnSoundOver(button_over_pcm, button_over_pcm_size, SOUND_PCM, Settings.sfxvolume); - GuiSound btnClick(button_click2_pcm, button_click2_pcm_size, SOUND_PCM, Settings.sfxvolume); + GuiSound btnSoundOver(button_over_pcm, button_over_pcm_size, Settings.sfxvolume); + // because destroy GuiSound must wait while sound playing is finished, we use a global sound + if(!btnClick2) btnClick2=new GuiSound(button_click2_pcm, button_click2_pcm_size, Settings.sfxvolume); + // GuiSound btnClick(button_click2_pcm, button_click2_pcm_size, Settings.sfxvolume); char imgPath[100]; snprintf(imgPath, sizeof(imgPath), "%sbutton_dialogue_box.png", CFG.theme_path); @@ -2535,7 +2550,7 @@ int ProgressUpdateWindow() { btn1Txt.SetWidescreen(CFG.widescreen); btn1Img.SetWidescreen(CFG.widescreen); } - GuiButton btn1(&btn1Img,&btn1Img, 2, 4, 0, -40, &trigA, &btnSoundOver, &btnClick,1); + GuiButton btn1(&btn1Img,&btn1Img, 2, 4, 0, -40, &trigA, &btnSoundOver, btnClick2,1); btn1.SetLabel(&btn1Txt); btn1.SetState(STATE_SELECTED); @@ -2800,7 +2815,9 @@ int ProgressUpdateWindow() { promptWindow.SetPosition(0, -10); GuiSound btnSoundOver(button_over_pcm, button_over_pcm_size, SOUND_PCM, Settings.sfxvolume); - GuiSound btnClick(button_click2_pcm, button_click2_pcm_size, SOUND_PCM, Settings.sfxvolume); + // because destroy GuiSound must wait while sound playing is finished, we use a global sound + if(!btnClick2) btnClick2=new GuiSound(button_click2_pcm, button_click2_pcm_size, SOUND_PCM, Settings.sfxvolume); + // GuiSound btnClick(button_click2_pcm, button_click2_pcm_size, SOUND_PCM, Settings.sfxvolume); char imgPath[100]; snprintf(imgPath, sizeof(imgPath), "%sbutton_dialogue_box.png", CFG.theme_path); @@ -3103,8 +3120,10 @@ int CodeDownload(const char *id) { promptWindow.SetAlignment(ALIGN_CENTRE, ALIGN_MIDDLE); promptWindow.SetPosition(0, -10); - GuiSound btnSoundOver(button_over_pcm, button_over_pcm_size, SOUND_PCM, Settings.sfxvolume); - GuiSound btnClick(button_click2_pcm, button_click2_pcm_size, SOUND_PCM, Settings.sfxvolume); + GuiSound btnSoundOver(button_over_pcm, button_over_pcm_size, Settings.sfxvolume); + // because destroy GuiSound must wait while sound playing is finished, we use a global sound + if(!btnClick2) btnClick2=new GuiSound(button_click2_pcm, button_click2_pcm_size, Settings.sfxvolume); + // GuiSound btnClick(button_click2_pcm, button_click2_pcm_size, Settings.sfxvolume); char imgPath[100]; snprintf(imgPath, sizeof(imgPath), "%sbutton_dialogue_box.png", CFG.theme_path); @@ -3142,7 +3161,7 @@ int CodeDownload(const char *id) { btn1Txt.SetWidescreen(CFG.widescreen); btn1Img.SetWidescreen(CFG.widescreen); } - GuiButton btn1(&btn1Img,&btn1Img, 2, 4, 0, -40, &trigA, &btnSoundOver, &btnClick,1); + GuiButton btn1(&btn1Img,&btn1Img, 2, 4, 0, -40, &trigA, &btnSoundOver, btnClick2,1); btn1.SetLabel(&btn1Txt); btn1.SetState(STATE_SELECTED); @@ -3278,8 +3297,10 @@ HBCWindowPrompt(const char *name, const char *coder, const char *version, GuiTrigger trigD; trigD.SetButtonOnlyTrigger(-1, WPAD_BUTTON_DOWN | WPAD_CLASSIC_BUTTON_DOWN, PAD_BUTTON_DOWN); - GuiSound btnSoundOver(button_over_pcm, button_over_pcm_size, SOUND_PCM, Settings.sfxvolume); - GuiSound btnClick(button_click2_pcm, button_click2_pcm_size, SOUND_PCM, Settings.sfxvolume); + GuiSound btnSoundOver(button_over_pcm, button_over_pcm_size, Settings.sfxvolume); + // because destroy GuiSound must wait while sound playing is finished, we use a global sound + if(!btnClick2) btnClick2=new GuiSound(button_click2_pcm, button_click2_pcm_size, Settings.sfxvolume); + // GuiSound btnClick(button_click2_pcm, button_click2_pcm_size, Settings.sfxvolume); char imgPath[100]; snprintf(imgPath, sizeof(imgPath), "%sbutton_dialogue_box.png", CFG.theme_path); GuiImageData btnOutline(imgPath, button_dialogue_box_png); @@ -3312,7 +3333,7 @@ HBCWindowPrompt(const char *name, const char *coder, const char *version, arrowUpBtn.SetTrigger(&trigA); arrowUpBtn.SetTrigger(&trigU); arrowUpBtn.SetEffectOnOver(EFFECT_SCALE, 50, 130); - arrowUpBtn.SetSoundClick(&btnClick); + arrowUpBtn.SetSoundClick(btnClick2); GuiButton arrowDownBtn(arrowDownImg.GetWidth(), arrowDownImg.GetHeight()); arrowDownBtn.SetImage(&arrowDownImg); @@ -3321,7 +3342,7 @@ HBCWindowPrompt(const char *name, const char *coder, const char *version, arrowDownBtn.SetTrigger(&trigA); arrowDownBtn.SetTrigger(&trigD); arrowDownBtn.SetEffectOnOver(EFFECT_SCALE, 50, 130); - arrowDownBtn.SetSoundClick(&btnClick); + arrowDownBtn.SetSoundClick(btnClick2); GuiImageData *iconData =NULL; GuiImage *iconImg =NULL; @@ -3415,7 +3436,7 @@ HBCWindowPrompt(const char *name, const char *coder, const char *version, btn1Img.SetWidescreen(CFG.widescreen); } - GuiButton btn1(&btn1Img, &btn1Img, 0,3,0,0,&trigA,&btnSoundOver,&btnClick,1); + GuiButton btn1(&btn1Img, &btn1Img, 0,3,0,0,&trigA,&btnSoundOver,btnClick2,1); btn1.SetLabel(&btn1Txt); btn1.SetState(STATE_SELECTED); @@ -3425,7 +3446,7 @@ HBCWindowPrompt(const char *name, const char *coder, const char *version, btn2Txt.SetWidescreen(CFG.widescreen); btn2Img.SetWidescreen(CFG.widescreen); } - GuiButton btn2(&btn2Img, &btn2Img, 0,3,0,0,&trigA,&btnSoundOver,&btnClick,1); + GuiButton btn2(&btn2Img, &btn2Img, 0,3,0,0,&trigA,&btnSoundOver,btnClick2,1); btn2.SetLabel(&btn2Txt); btn2.SetTrigger(&trigB); diff --git a/source/prompts/TitleBrowser.cpp b/source/prompts/TitleBrowser.cpp index b5b86e10..f28df747 100644 --- a/source/prompts/TitleBrowser.cpp +++ b/source/prompts/TitleBrowser.cpp @@ -230,8 +230,10 @@ int TitleBrowser(u32 type) { if (IsNetworkInit()) ResumeNetworkWait(); - GuiSound btnSoundOver(button_over_pcm, button_over_pcm_size, SOUND_PCM, Settings.sfxvolume); - GuiSound btnClick(button_click2_pcm, button_click2_pcm_size, SOUND_PCM, Settings.sfxvolume); + GuiSound btnSoundOver(button_over_pcm, button_over_pcm_size, Settings.sfxvolume); + // because destroy GuiSound must wait while sound playing is finished, we use a global sound + if(!btnClick2) btnClick2=new GuiSound(button_click2_pcm, button_click2_pcm_size, Settings.sfxvolume); + // GuiSound btnClick(button_click2_pcm, button_click2_pcm_size, Settings.sfxvolume); char imgPath[100]; @@ -265,7 +267,7 @@ int TitleBrowser(u32 type) { cancelBtnTxt.SetWidescreen(CFG.widescreen); cancelBtnImg.SetWidescreen(CFG.widescreen); } - GuiButton cancelBtn(&cancelBtnImg,&cancelBtnImg, 2, 3, 180, 400, &trigA, &btnSoundOver, &btnClick,1); + GuiButton cancelBtn(&cancelBtnImg,&cancelBtnImg, 2, 3, 180, 400, &trigA, &btnSoundOver, btnClick2,1); cancelBtn.SetScale(0.9); cancelBtn.SetLabel(&cancelBtnTxt); cancelBtn.SetTrigger(&trigB); diff --git a/source/prompts/filebrowser.cpp b/source/prompts/filebrowser.cpp index f1e382f9..b6ab7d68 100644 --- a/source/prompts/filebrowser.cpp +++ b/source/prompts/filebrowser.cpp @@ -304,8 +304,10 @@ int BrowseDevice(char * Path, int Path_size, int Flags, FILTERCASCADE *Filter/*= GuiTrigger trigB; trigB.SetButtonOnlyTrigger(-1, WPAD_BUTTON_B | WPAD_CLASSIC_BUTTON_B, PAD_BUTTON_B); - GuiSound btnSoundOver(button_over_pcm, button_over_pcm_size, SOUND_PCM, Settings.sfxvolume); - GuiSound btnClick(button_click2_pcm, button_click2_pcm_size, SOUND_PCM, Settings.sfxvolume); + GuiSound btnSoundOver(button_over_pcm, button_over_pcm_size, Settings.sfxvolume); + // because destroy GuiSound must wait while sound playing is finished, we use a global sound + if(!btnClick2) btnClick2=new GuiSound(button_click2_pcm, button_click2_pcm_size, Settings.sfxvolume); + // GuiSound btnClick(button_click2_pcm, button_click2_pcm_size, Settings.sfxvolume); GuiImageData folderImgData(icon_folder_png); GuiImage folderImg(&folderImgData); @@ -354,7 +356,7 @@ int BrowseDevice(char * Path, int Path_size, int Flags, FILTERCASCADE *Filter/*= okBtnTxt.SetWidescreen(CFG.widescreen); okBtnImg.SetWidescreen(CFG.widescreen); } - GuiButton okBtn(&okBtnImg,&okBtnImg, 0, 4, 40, -35, &trigA, &btnSoundOver, &btnClick,1); + GuiButton okBtn(&okBtnImg,&okBtnImg, 0, 4, 40, -35, &trigA, &btnSoundOver, btnClick2,1); okBtn.SetLabel(&okBtnTxt); GuiFileBrowser fileBrowser(396, 248); diff --git a/source/prompts/gameinfo.cpp b/source/prompts/gameinfo.cpp index cc9e734b..a03c7615 100644 --- a/source/prompts/gameinfo.cpp +++ b/source/prompts/gameinfo.cpp @@ -148,8 +148,8 @@ int showGameInfo(char *ID) { txtWindow.SetAlignment(ALIGN_CENTRE, ALIGN_RIGHT); txtWindow.SetPosition(95, 55); - GuiSound btnSoundOver(button_over_pcm, button_over_pcm_size, SOUND_PCM, Settings.sfxvolume); - GuiSound btnClick(button_click2_pcm, button_click2_pcm_size, SOUND_PCM, Settings.sfxvolume); + GuiSound btnSoundOver(button_over_pcm, button_over_pcm_size, Settings.sfxvolume); + GuiSound btnClick(button_click2_pcm, button_click2_pcm_size, Settings.sfxvolume); char imgPath[100]; snprintf(imgPath, sizeof(imgPath), "%sbutton_dialogue_box.png", CFG.theme_path); GuiImageData btnOutline(imgPath, button_dialogue_box_png); diff --git a/source/ramdisk/ramdisk.cpp b/source/ramdisk/ramdisk.cpp index bd0b1c13..77478636 100644 --- a/source/ramdisk/ramdisk.cpp +++ b/source/ramdisk/ramdisk.cpp @@ -11,7 +11,6 @@ #define NAMELENMAX 0x80 #define MAXPATHLEN 0x100 -#define FPRINTF(f, ...) {FILE*_fp=fopen("SD:/log.log", "a"); if(_fp) { fprintf(_fp, "%s(%i):" f "\n", __FILE__, __LINE__, ##__VA_ARGS__); fclose(_fp);}} @@ -533,7 +532,6 @@ static inline RAMDISK_PARTITION* ramdiskFS_getPartitionFromPath(const char* path //--------------------------------------------------------------------------------- static int ramdiskFS_open_r(struct _reent *r, void *file_Struct, const char *path, int flags, int mode) { //--------------------------------------------------------------------------------- -FPRINTF("ramdiskFS_open_r(%s)", path); FILE_STRUCT *fileStruct = (FILE_STRUCT*)file_Struct; @@ -543,7 +541,6 @@ FPRINTF("ramdiskFS_open_r(%s)", path); r->_errno = ENODEV; return -1; } -FPRINTF("ramdiskFS_open_r Partition found"); if ((flags & 0x03) == O_RDONLY) { // Open the file for read-only access @@ -569,14 +566,12 @@ FPRINTF("ramdiskFS_open_r Partition found"); r->_errno = EEXIST; return -1; } -FPRINTF("ok"); // It should not be a directory if we're openning a file, if (entry && entry->IsDir()) { r->_errno = EISDIR; return -1; } -FPRINTF("ok"); fileStruct->isLink = entry ? entry->IsLink() : false; fileStruct->file = entry ? entry->IsFile() : NULL; @@ -600,7 +595,6 @@ FPRINTF("ok"); return -1; } } -FPRINTF("ok"); if(fileStruct->file) { fileStruct->current_pos = 0; @@ -610,7 +604,6 @@ FPRINTF("ok"); if (flags & O_APPEND) fileStruct->current_pos = fileStruct->file->file_len; return 0; -FPRINTF("ramdiskFS_open_r ok"); } r->_errno = ENOENT; return(-1); @@ -641,7 +634,6 @@ static off_t ramdiskFS_seek_r(struct _reent *r, int fd, off_t pos, int dir) { //--------------------------------------------------------------------------------- //need check for eof here... FILE_STRUCT *fileStruct = (FILE_STRUCT*)fd; -FPRINTF("ramdiskFS_seek_r(%s)", fileStruct->file->name); switch(dir) { @@ -663,7 +655,6 @@ FPRINTF("ramdiskFS_seek_r(%s)", fileStruct->file->name); //--------------------------------------------------------------------------------- static int ramdiskFS_fstat_r(struct _reent *r, int fd, struct stat *st) { //--------------------------------------------------------------------------------- -FPRINTF("ramdiskFS_fstat_r"); FILE_STRUCT *fileStruct = (FILE_STRUCT*)fd; st->st_mode = fileStruct->isLink ? S_IFLNK : S_IFREG; @@ -674,7 +665,6 @@ FPRINTF("ramdiskFS_fstat_r"); //--------------------------------------------------------------------------------- static int ramdiskFS_stat_r(struct _reent *r, const char *file, struct stat *st) { //--------------------------------------------------------------------------------- -FPRINTF("ramdiskFS_stat_r(%s)", file); FILE_STRUCT fileStruct; DIR_STRUCT dirStruct; DIR_ITER dirState; @@ -700,7 +690,6 @@ FPRINTF("ramdiskFS_stat_r(%s)", file); //--------------------------------------------------------------------------------- static int ramdiskFS_unlink_r(struct _reent *r, const char *name) { //--------------------------------------------------------------------------------- -FPRINTF("ramdiskFS_unlink_r(%s)", name); RAMDISK_PARTITION *partition = ramdiskFS_getPartitionFromPath(name); if ( partition == NULL ) { @@ -744,7 +733,6 @@ FPRINTF("ramdiskFS_unlink_r(%s)", name); //--------------------------------------------------------------------------------- static int ramdiskFS_chdir_r(struct _reent *r, const char *name) { //--------------------------------------------------------------------------------- -FPRINTF("ramdiskFS_chdir_r(%s)", name); DIR_STRUCT dirStruct; DIR_ITER dirState; dirState.dirStruct=&dirStruct; @@ -765,14 +753,12 @@ FPRINTF("ramdiskFS_chdir_r(%s)", name); } partition->cwd = dirStruct.dir; ramdiskFS_dirclose_r(r, &dirState); -FPRINTF("ok"); return 0; } //--------------------------------------------------------------------------------- static int ramdiskFS_mkdir_r(struct _reent *r, const char *path, int mode) { //--------------------------------------------------------------------------------- -FPRINTF("ramdiskFS_mkdir_r(%s)", path); RAMDISK_PARTITION *partition = ramdiskFS_getPartitionFromPath(path); if ( partition == NULL ) { @@ -802,12 +788,10 @@ FPRINTF("ramdiskFS_mkdir_r(%s)", path); static DIR_ITER* ramdiskFS_diropen_r(struct _reent *r, DIR_ITER *dirState, const char *path) { //--------------------------------------------------------------------------------- - FPRINTF("DirOpen %s", path); DIR_STRUCT *dirStruct = (DIR_STRUCT*)dirState->dirStruct; char *cptr; RAMDISK_PARTITION *partition = ramdiskFS_getPartitionFromPath(path); - FPRINTF("partition %p", partition); if ( partition == NULL ) { r->_errno = ENODEV; @@ -828,7 +812,6 @@ static DIR_ITER* ramdiskFS_diropen_r(struct _reent *r, DIR_ITER *dirState, const dirStruct->dir = partition->cwd; //else use current working dir RAMDISK_BASE_ENTRY *entry = dirStruct->dir->FindEntry(path); - FPRINTF("entry %p", entry); if(entry==NULL) { r->_errno = ENOENT; @@ -860,20 +843,15 @@ static int ramdiskFS_dirnext_r(struct _reent *r, DIR_ITER *dirState, char *filen DIR_STRUCT *dirStruct = (DIR_STRUCT*)dirState->dirStruct; // RAMDISK_BASE_ENTRY **dirStruct = (RAMDISK_BASE_ENTRY**)dirState->dirStruct; - FPRINTF("DirNext"); - if(dirStruct->current_entry) { - FPRINTF("current_entry = %s",dirStruct->current_entry->name); strcpy(filename, dirStruct->current_entry->name); if(dirStruct->current_entry->IsDir()) { - FPRINTF("IsDir"); if(st) st->st_mode=S_IFDIR; } else { - FPRINTF("IsFile"); if(st) st->st_mode=0; } dirStruct->current_entry = dirStruct->current_entry->next; @@ -947,7 +925,6 @@ extern "C" void ramdiskUnmount(const char *mountpoint) { //--------------------------------------------------------------------------------- int ramdiskFS_Mount(const char *mountpoint, void *handle) { //--------------------------------------------------------------------------------- - FPRINTF("Mount %s", mountpoint); devoptab_t* devops; char* nameCopy; RAMDISK_PARTITION** partition; @@ -989,14 +966,12 @@ int ramdiskFS_Mount(const char *mountpoint, void *handle) { else *partition = new RAMDISK_PARTITION(Mountpoint, true); devops->deviceData = partition; - FPRINTF("devops=%p nameCopy=%p(%s) partition=%p", devops, nameCopy, nameCopy, partition); if(AddDevice(devops)<0) { free(devops); return false; } - FPRINTF("mounted"); return true; diff --git a/source/settings/Settings.cpp b/source/settings/Settings.cpp index f4417086..e4b5b6b3 100644 --- a/source/settings/Settings.cpp +++ b/source/settings/Settings.cpp @@ -71,9 +71,11 @@ int MenuSettings() int slidedirection = FADE; - GuiSound btnSoundOver(button_over_pcm, button_over_pcm_size, SOUND_PCM, Settings.sfxvolume); - GuiSound btnClick(button_click2_pcm, button_click2_pcm_size, SOUND_PCM, Settings.sfxvolume); - GuiSound btnClick1(button_click_pcm, button_click_pcm_size, SOUND_PCM, Settings.sfxvolume); + GuiSound btnSoundOver(button_over_pcm, button_over_pcm_size, Settings.sfxvolume); + // because destroy GuiSound must wait while sound playing is finished, we use a global sound + if(!btnClick2) btnClick2=new GuiSound(button_click2_pcm, button_click2_pcm_size, Settings.sfxvolume); + // GuiSound btnClick(button_click2_pcm, button_click2_pcm_size, Settings.sfxvolume); + GuiSound btnClick1(button_click_pcm, button_click_pcm_size, Settings.sfxvolume); char imgPath[100]; @@ -135,7 +137,7 @@ int MenuSettings() backBtnTxt.SetWidescreen(CFG.widescreen); backBtnImg.SetWidescreen(CFG.widescreen); } - GuiButton backBtn(&backBtnImg,&backBtnImg, 2, 3, -180, 400, &trigA, &btnSoundOver, &btnClick,1); + GuiButton backBtn(&backBtnImg,&backBtnImg, 2, 3, -180, 400, &trigA, &btnSoundOver, btnClick2,1); backBtn.SetLabel(&backBtnTxt); backBtn.SetTrigger(&trigB); @@ -184,7 +186,7 @@ int MenuSettings() GoLeftBtn.SetPosition(25, -25); GoLeftBtn.SetImage(&GoLeftImg); GoLeftBtn.SetSoundOver(&btnSoundOver); - GoLeftBtn.SetSoundClick(&btnClick); + GoLeftBtn.SetSoundClick(btnClick2); GoLeftBtn.SetEffectGrow(); GoLeftBtn.SetTrigger(&trigA); GoLeftBtn.SetTrigger(&trigL); @@ -196,7 +198,7 @@ int MenuSettings() GoRightBtn.SetPosition(-25, -25); GoRightBtn.SetImage(&GoRightImg); GoRightBtn.SetSoundOver(&btnSoundOver); - GoRightBtn.SetSoundClick(&btnClick); + GoRightBtn.SetSoundClick(btnClick2); GoRightBtn.SetEffectGrow(); GoRightBtn.SetTrigger(&trigA); GoRightBtn.SetTrigger(&trigR); @@ -665,15 +667,9 @@ int MenuSettings() { cfg_save_global(); optionBrowser2.SetState(STATE_DISABLED); - s32 thetimeofbg = bgMusic->GetPlayTime(); - bgMusic->Stop(); + bgMusic->Pause(); choice = WindowExitPrompt(tr("Exit USB Loader GX?"),0, tr("Back to Loader"),tr("Wii Menu"),tr("Back"),0); - if (!strcmp("", Settings.oggload_path) || !strcmp("notset", Settings.ogg_path)) - bgMusic->Play(); - else - bgMusic->PlayOggFile(Settings.ogg_path); - bgMusic->SetPlayTime(thetimeofbg); - SetVolumeOgg(255*(Settings.volume/100.0)); + bgMusic->Resume(); if (choice == 3) Sys_LoadMenu(); // Back to System Menu else if (choice == 2) @@ -908,15 +904,9 @@ int MenuSettings() { cfg_save_global(); optionBrowser2.SetState(STATE_DISABLED); - s32 thetimeofbg = bgMusic->GetPlayTime(); - bgMusic->Stop(); + bgMusic->Pause(); choice = WindowExitPrompt(tr("Exit USB Loader GX?"),0, tr("Back to Loader"),tr("Wii Menu"),tr("Back"),0); - if (!strcmp("", Settings.oggload_path) || !strcmp("notset", Settings.ogg_path)) - bgMusic->Play(); - else - bgMusic->PlayOggFile(Settings.ogg_path); - bgMusic->SetPlayTime(thetimeofbg); - SetVolumeOgg(255*(Settings.volume/100.0)); + bgMusic->Resume(); if (choice == 3) Sys_LoadMenu(); // Back to System Menu if (choice == 2) @@ -1060,15 +1050,9 @@ int MenuSettings() { cfg_save_global(); optionBrowser2.SetState(STATE_DISABLED); - s32 thetimeofbg = bgMusic->GetPlayTime(); - bgMusic->Stop(); + bgMusic->Pause(); choice = WindowExitPrompt(tr("Exit USB Loader GX?"),0, tr("Back to Loader"),tr("Wii Menu"),tr("Back"),0); - if (!strcmp("", Settings.oggload_path) || !strcmp("notset", Settings.ogg_path)) - bgMusic->Play(); - else - bgMusic->PlayOggFile(Settings.ogg_path); - bgMusic->SetPlayTime(thetimeofbg); - SetVolumeOgg(255*(Settings.volume/100.0)); + bgMusic->Resume(); if (choice == 3) Sys_LoadMenu(); // Back to System Menu else if (choice == 2) @@ -1238,15 +1222,9 @@ int MenuSettings() { cfg_save_global(); optionBrowser2.SetState(STATE_DISABLED); - s32 thetimeofbg = bgMusic->GetPlayTime(); - bgMusic->Stop(); + bgMusic->Pause(); choice = WindowExitPrompt(tr("Exit USB Loader GX?"),0, tr("Back to Loader"),tr("Wii Menu"),tr("Back"),0); - if (!strcmp("", Settings.oggload_path) || !strcmp("notset", Settings.ogg_path)) - bgMusic->Play(); - else - bgMusic->PlayOggFile(Settings.ogg_path); - bgMusic->SetPlayTime(thetimeofbg); - SetVolumeOgg(255*(Settings.volume/100.0)); + bgMusic->Resume(); if (choice == 3) Sys_LoadMenu(); // Back to System Menu else if (choice == 2) @@ -1298,7 +1276,7 @@ int MenuSettings() Settings.volume += 10; if (Settings.volume > 100) Settings.volume = 0; - SetVolumeOgg(255*(Settings.volume/100.0)); + bgMusic->SetVolume(Settings.volume); } if (Settings.volume > 0) options2.SetValue(Idx,"%i", Settings.volume); @@ -1315,7 +1293,7 @@ int MenuSettings() if (Settings.sfxvolume > 100) Settings.sfxvolume = 0; btnSoundOver.SetVolume(Settings.sfxvolume); - btnClick.SetVolume(Settings.sfxvolume); + btnClick2->SetVolume(Settings.sfxvolume); btnClick1.SetVolume(Settings.sfxvolume); } if (Settings.sfxvolume > 0) @@ -1420,15 +1398,9 @@ int MenuSettings() { cfg_save_global(); optionBrowser2.SetState(STATE_DISABLED); - s32 thetimeofbg = bgMusic->GetPlayTime(); - bgMusic->Stop(); + bgMusic->Pause(); choice = WindowExitPrompt(tr("Exit USB Loader GX?"),0, tr("Back to Loader"),tr("Wii Menu"),tr("Back"),0); - if (!strcmp("", Settings.oggload_path) || !strcmp("notset", Settings.ogg_path)) - bgMusic->Play(); - else - bgMusic->PlayOggFile(Settings.ogg_path); - bgMusic->SetPlayTime(thetimeofbg); - SetVolumeOgg(255*(Settings.volume/100.0)); + bgMusic->Resume(); if (choice == 3) Sys_LoadMenu(); // Back to System Menu else if (choice == 2) @@ -2010,15 +1982,9 @@ int MenuSettings() { cfg_save_global(); optionBrowser2.SetState(STATE_DISABLED); - s32 thetimeofbg = bgMusic->GetPlayTime(); - bgMusic->Stop(); + bgMusic->Pause(); choice = WindowExitPrompt(tr("Exit USB Loader GX?"),0, tr("Back to Loader"),tr("Wii Menu"),tr("Back"),0); - if (!strcmp("", Settings.oggload_path) || !strcmp("notset", Settings.ogg_path)) - bgMusic->Play(); - else - bgMusic->PlayOggFile(Settings.ogg_path); - bgMusic->SetPlayTime(thetimeofbg); - SetVolumeOgg(255*(Settings.volume/100.0)); + bgMusic->Resume(); if (choice == 3) Sys_LoadMenu(); // Back to System Menu @@ -2070,9 +2036,11 @@ int GameSettings(struct discHdr * header) - GuiSound btnSoundOver(button_over_pcm, button_over_pcm_size, SOUND_PCM, Settings.sfxvolume); - GuiSound btnClick(button_click2_pcm, button_click2_pcm_size, SOUND_PCM, Settings.sfxvolume); - GuiSound btnClick1(button_click_pcm, button_click_pcm_size, SOUND_PCM, Settings.sfxvolume); + GuiSound btnSoundOver(button_over_pcm, button_over_pcm_size, Settings.sfxvolume); + // because destroy GuiSound must wait while sound playing is finished, we use a global sound + if(!btnClick2) btnClick2=new GuiSound(button_click2_pcm, button_click2_pcm_size, Settings.sfxvolume); + // GuiSound btnClick(button_click2_pcm, button_click2_pcm_size, Settings.sfxvolume); + GuiSound btnClick1(button_click_pcm, button_click_pcm_size, Settings.sfxvolume); char imgPath[100]; @@ -2124,7 +2092,7 @@ int GameSettings(struct discHdr * header) backBtnTxt.SetWidescreen(CFG.widescreen); backBtnImg.SetWidescreen(CFG.widescreen); } - GuiButton backBtn(&backBtnImg,&backBtnImg, 2, 3, -180, 400, &trigA, &btnSoundOver, &btnClick,1); + GuiButton backBtn(&backBtnImg,&backBtnImg, 2, 3, -180, 400, &trigA, &btnSoundOver, btnClick2,1); backBtn.SetLabel(&backBtnTxt); backBtn.SetTrigger(&trigB); @@ -2139,7 +2107,7 @@ int GameSettings(struct discHdr * header) saveBtnTxt.SetWidescreen(CFG.widescreen); saveBtnImg.SetWidescreen(CFG.widescreen); } - GuiButton saveBtn(&saveBtnImg,&saveBtnImg, 2, 3, 180, 400, &trigA, &btnSoundOver, &btnClick,1); + GuiButton saveBtn(&saveBtnImg,&saveBtnImg, 2, 3, 180, 400, &trigA, &btnSoundOver, btnClick2,1); saveBtn.SetLabel(&saveBtnTxt); @@ -2384,15 +2352,9 @@ int GameSettings(struct discHdr * header) { cfg_save_global(); optionBrowser2.SetState(STATE_DISABLED); - s32 thetimeofbg = bgMusic->GetPlayTime(); - bgMusic->Stop(); + bgMusic->Pause(); choice = WindowExitPrompt(tr("Exit USB Loader GX?"),0, tr("Back to Loader"),tr("Wii Menu"),tr("Back"),0); - if (!strcmp("", Settings.oggload_path) || !strcmp("notset", Settings.ogg_path)) - bgMusic->Play(); - else - bgMusic->PlayOggFile(Settings.ogg_path); - bgMusic->SetPlayTime(thetimeofbg); - SetVolumeOgg(255*(Settings.volume/100.0)); + bgMusic->Resume(); if (choice == 3) Sys_LoadMenu(); // Back to System Menu else if (choice == 2) @@ -2654,15 +2616,9 @@ int GameSettings(struct discHdr * header) { cfg_save_global(); optionBrowser2.SetState(STATE_DISABLED); - s32 thetimeofbg = bgMusic->GetPlayTime(); - bgMusic->Stop(); + bgMusic->Pause(); choice = WindowExitPrompt(tr("Exit USB Loader GX?"),0, tr("Back to Loader"),tr("Wii Menu"),tr("Back"),0); - if (!strcmp("", Settings.oggload_path) || !strcmp("notset", Settings.ogg_path)) - bgMusic->Play(); - else - bgMusic->PlayOggFile(Settings.ogg_path); - bgMusic->SetPlayTime(thetimeofbg); - SetVolumeOgg(255*(Settings.volume/100.0)); + bgMusic->Resume(); if (choice == 3) Sys_LoadMenu(); // Back to System Menu else if (choice == 2) @@ -2860,24 +2816,9 @@ int GameSettings(struct discHdr * header) { cfg_save_global(); optionBrowser2.SetState(STATE_DISABLED); - s32 thetimeofbg = bgMusic->GetPlayTime(); - bgMusic->Stop(); + bgMusic->Pause(); choice = WindowExitPrompt(tr("Exit USB Loader GX?"),0, tr("Back to Loader"),tr("Wii Menu"),tr("Back"),0); - /* - // if language has changed, reload titles - int opt_langnew = 0; - game_cfg = CFG_get_game_opt(header->id); - if (game_cfg) opt_langnew = game_cfg->language; - if (Settings.titlesOverride==1 && opt_lang != opt_langnew) - OpenXMLDatabase(Settings.titlestxt_path, Settings.db_language, Settings.db_JPtoEN, false, Settings.titlesOverride==1?true:false, true); // open file, reload titles, keep in memory - // titles are refreshed in menu.cpp as soon as this function returns - */ - if (!strcmp("", Settings.oggload_path) || !strcmp("notset", Settings.ogg_path)) - bgMusic->Play(); - else - bgMusic->PlayOggFile(Settings.ogg_path); - bgMusic->SetPlayTime(thetimeofbg); - SetVolumeOgg(255*(Settings.volume/100.0)); + bgMusic->Resume(); if (choice == 3) Sys_LoadMenu(); // Back to System Menu diff --git a/source/settings/SettingsPrompts.cpp b/source/settings/SettingsPrompts.cpp index 5590bd70..6a87e2c3 100644 --- a/source/settings/SettingsPrompts.cpp +++ b/source/settings/SettingsPrompts.cpp @@ -14,6 +14,7 @@ #include "fatmounter.h" #include "filelist.h" #include "sys.h" +#include "menu.h" /*** Extern variables ***/ @@ -36,8 +37,10 @@ bool MenuOGG() { int scrollon, nothingchanged = 0; bool returnhere = false; - GuiSound btnSoundOver(button_over_pcm, button_over_pcm_size, SOUND_PCM, Settings.sfxvolume); - GuiSound btnClick(button_click2_pcm, button_click2_pcm_size, SOUND_PCM, Settings.sfxvolume); + GuiSound btnSoundOver(button_over_pcm, button_over_pcm_size, Settings.sfxvolume); + // because destroy GuiSound must wait while sound playing is finished, we use a global sound + if(!btnClick2) btnClick2=new GuiSound(button_click2_pcm, button_click2_pcm_size, Settings.sfxvolume); + // GuiSound btnClick(button_click2_pcm, button_click2_pcm_size, Settings.sfxvolume); char imgPath[100]; @@ -73,7 +76,7 @@ bool MenuOGG() { pathBtn.SetPosition(0,28); pathBtn.SetLabel(&titleTxt); pathBtn.SetSoundOver(&btnSoundOver); - pathBtn.SetSoundClick(&btnClick); + pathBtn.SetSoundClick(btnClick2); pathBtn.SetTrigger(&trigA); pathBtn.SetEffectGrow(); @@ -94,7 +97,7 @@ bool MenuOGG() { backBtn.SetLabel(&backBtnTxt); backBtn.SetImage(&backBtnImg); backBtn.SetSoundOver(&btnSoundOver); - backBtn.SetSoundClick(&btnClick); + backBtn.SetSoundClick(btnClick2); backBtn.SetTrigger(&trigA); backBtn.SetTrigger(&trigB); backBtn.SetEffectGrow(); @@ -112,7 +115,7 @@ bool MenuOGG() { defaultBtn.SetLabel(&defaultBtnTxt); defaultBtn.SetImage(&defaultBtnImg); defaultBtn.SetSoundOver(&btnSoundOver); - defaultBtn.SetSoundClick(&btnClick); + defaultBtn.SetSoundClick(btnClick2); defaultBtn.SetTrigger(&trigA); defaultBtn.SetEffectGrow(); @@ -145,7 +148,7 @@ bool MenuOGG() { playBtn.SetPosition(50, 400); playBtn.SetImage(&playBtnImg); playBtn.SetSoundOver(&btnSoundOver); - playBtn.SetSoundClick(&btnClick); + playBtn.SetSoundClick(btnClick2); playBtn.SetTrigger(&trigA); playBtn.SetTrigger(&trigPlus); playBtn.SetEffectGrow(); @@ -157,7 +160,7 @@ bool MenuOGG() { stopBtn.SetPosition(-15, 400); stopBtn.SetImage(&stopBtnImg); stopBtn.SetSoundOver(&btnSoundOver); - stopBtn.SetSoundClick(&btnClick); + stopBtn.SetSoundClick(btnClick2); stopBtn.SetTrigger(&trigA); stopBtn.SetTrigger(&trigMinus); stopBtn.SetEffectGrow(); @@ -187,11 +190,12 @@ bool MenuOGG() { if (backBtn.GetState() == STATE_CLICKED) { if (nothingchanged == 1 && countoggs > 0) { - if (!strcmp("", Settings.oggload_path) || !strcmp("notset", Settings.ogg_path)) { - bgMusic->Play(); + if (strcmp("", Settings.oggload_path) && strcmp("notset", Settings.ogg_path)) { + bgMusic->Load(Settings.ogg_path); } else { - bgMusic->PlayOggFile(Settings.ogg_path); - } + bgMusic->Load(bg_music_ogg, bg_music_ogg_size, true); + } + bgMusic->Play(); } backBtn.ResetState(); break; @@ -201,8 +205,9 @@ bool MenuOGG() { choice = WindowPrompt(tr("Loading standard music."),0,tr("OK"), tr("Cancel")); if (choice == 1) { sprintf(Settings.ogg_path, "notset"); + bgMusic->Load(bg_music_ogg, bg_music_ogg_size, true); bgMusic->Play(); - SetVolumeOgg(255*(Settings.volume/100.0)); + bgMusic->SetVolume(Settings.volume); cfg_save_global(); } defaultBtn.ResetState(); @@ -255,20 +260,18 @@ bool MenuOGG() { if (ret>=0) { choice = WindowPrompt(tr("Set as backgroundmusic?"),GetFileName(ret),tr("Yes"),tr("No")); if (choice == 1) { - StopOgg(); snprintf(fullpath,150,"%s%s",Settings.oggload_path,GetFileName(ret)); - choice = bgMusic->PlayOggFile(fullpath); - if (choice < 0) { + if (!bgMusic->Load(fullpath)) { WindowPrompt(tr("Not supported format!"), tr("Loading standard music."), tr("OK")); sprintf(Settings.ogg_path, "notset"); - bgMusic->Play(); - SetVolumeOgg(255*(Settings.volume/100.0)); } else { snprintf(Settings.ogg_path, sizeof(Settings.ogg_path), "%s", fullpath); cfg_save_global(); - SetVolumeOgg(255*(Settings.volume/100.0)); + bgMusic->SetVolume(Settings.volume); nothingchanged = 0; } + bgMusic->Play(); + bgMusic->SetVolume(Settings.volume); } optionBrowser4.SetFocus(1); } @@ -277,16 +280,11 @@ bool MenuOGG() { if (countoggs > 0) { ret = optionBrowser4.GetSelectedOption(); snprintf(fullpath, 150,"%s%s", Settings.oggload_path,GetFileName(ret)); - choice = bgMusic->PlayOggFile(fullpath); - if (choice < 0) { + if (!bgMusic->Load(fullpath)) { WindowPrompt(tr("Not supported format!"), tr("Loading standard music."), tr("OK")); - if (!strcmp("", Settings.oggload_path) || !strcmp("notset", Settings.ogg_path)) { - bgMusic->Play(); - } else { - bgMusic->PlayOggFile(Settings.ogg_path); - } } - SetVolumeOgg(255*(Settings.volume/100.0)); + bgMusic->Play(); + bgMusic->SetVolume(Settings.volume); nothingchanged = 1; optionBrowser4.SetFocus(1); } @@ -295,7 +293,7 @@ bool MenuOGG() { if (stopBtn.GetState() == STATE_CLICKED) { if (countoggs > 0) { - StopOgg(); + bgMusic->Stop(); nothingchanged = 1; optionBrowser4.SetFocus(1); } @@ -322,8 +320,10 @@ int MenuLanguageSelect() { int scrollon; int returnhere = 0; - GuiSound btnSoundOver(button_over_pcm, button_over_pcm_size, SOUND_PCM, Settings.sfxvolume); - GuiSound btnClick(button_click2_pcm, button_click2_pcm_size, SOUND_PCM, Settings.sfxvolume); + GuiSound btnSoundOver(button_over_pcm, button_over_pcm_size, Settings.sfxvolume); + // because destroy GuiSound must wait while sound playing is finished, we use a global sound + if(!btnClick2) btnClick2=new GuiSound(button_click2_pcm, button_click2_pcm_size, Settings.sfxvolume); + // GuiSound btnClick(button_click2_pcm, button_click2_pcm_size, Settings.sfxvolume); char imgPath[100]; @@ -354,7 +354,7 @@ int MenuLanguageSelect() { pathBtn.SetPosition(0,28); pathBtn.SetLabel(&titleTxt); pathBtn.SetSoundOver(&btnSoundOver); - pathBtn.SetSoundClick(&btnClick); + pathBtn.SetSoundClick(btnClick2); pathBtn.SetTrigger(&trigA); pathBtn.SetEffectGrow(); @@ -375,7 +375,7 @@ int MenuLanguageSelect() { backBtn.SetLabel(&backBtnTxt); backBtn.SetImage(&backBtnImg); backBtn.SetSoundOver(&btnSoundOver); - backBtn.SetSoundClick(&btnClick); + backBtn.SetSoundClick(btnClick2); backBtn.SetTrigger(&trigA); backBtn.SetTrigger(&trigB); backBtn.SetEffectGrow(); @@ -393,7 +393,7 @@ int MenuLanguageSelect() { defaultBtn.SetLabel(&defaultBtnTxt); defaultBtn.SetImage(&defaultBtnImg); defaultBtn.SetSoundOver(&btnSoundOver); - defaultBtn.SetSoundClick(&btnClick); + defaultBtn.SetSoundClick(btnClick2); defaultBtn.SetTrigger(&trigA); defaultBtn.SetEffectGrow(); @@ -410,7 +410,7 @@ int MenuLanguageSelect() { updateBtn.SetLabel(&updateBtnTxt); updateBtn.SetImage(&updateBtnImg); updateBtn.SetSoundOver(&btnSoundOver); - updateBtn.SetSoundClick(&btnClick); + updateBtn.SetSoundClick(btnClick2); updateBtn.SetTrigger(&trigA); updateBtn.SetEffectGrow(); diff --git a/source/settings/cfg.h b/source/settings/cfg.h index f4c4ab9d..3b0aff23 100644 --- a/source/settings/cfg.h +++ b/source/settings/cfg.h @@ -421,6 +421,7 @@ extern "C" { u8 discart; short gamesound; }; + extern struct SSettings Settings; void CFG_LoadGlobal(void); bool cfg_save_global(void); diff --git a/source/sounds/menuout.ogg b/source/sounds/menuout.ogg index e66f574ca70a507785d7566d640b7af86f811700..3d840b0e97ee62dcb79e53375b8af20129d126a4 100644 GIT binary patch literal 21077 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%0Dcm5O(g@aV_Cf&70bg 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 IB!o+%>4V!Bod5s; literal 11143 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 diff --git a/source/themes/Theme_Downloader.cpp b/source/themes/Theme_Downloader.cpp index 0d5106aa..f0afe614 100644 --- a/source/themes/Theme_Downloader.cpp +++ b/source/themes/Theme_Downloader.cpp @@ -119,8 +119,10 @@ static void Theme_Prompt(const char *title, const char *author, GuiImageData *th { bool leave = false; - GuiSound btnSoundOver(button_over_pcm, button_over_pcm_size, SOUND_PCM, Settings.sfxvolume); - GuiSound btnClick(button_click2_pcm, button_click2_pcm_size, SOUND_PCM, Settings.sfxvolume); + GuiSound btnSoundOver(button_over_pcm, button_over_pcm_size, Settings.sfxvolume); + // because destroy GuiSound must wait while sound playing is finished, we use a global sound + if(!btnClick2) btnClick2=new GuiSound(button_click2_pcm, button_click2_pcm_size, Settings.sfxvolume); + // GuiSound btnClick(button_click2_pcm, button_click2_pcm_size, Settings.sfxvolume); char imgPath[100]; snprintf(imgPath, sizeof(imgPath), "%sbutton_dialogue_box.png", CFG.theme_path); @@ -165,7 +167,7 @@ static void Theme_Prompt(const char *title, const char *author, GuiImageData *th downloadBtnTxt.SetWidescreen(CFG.widescreen); downloadBtnImg.SetWidescreen(CFG.widescreen); } - GuiButton downloadBtn(&downloadBtnImg,&downloadBtnImg, ALIGN_RIGHT, ALIGN_TOP, -5, 170, &trigA, &btnSoundOver, &btnClick,1); + GuiButton downloadBtn(&downloadBtnImg,&downloadBtnImg, ALIGN_RIGHT, ALIGN_TOP, -5, 170, &trigA, &btnSoundOver, btnClick2,1); downloadBtn.SetLabel(&downloadBtnTxt); downloadBtn.SetScale(0.9); @@ -177,7 +179,7 @@ static void Theme_Prompt(const char *title, const char *author, GuiImageData *th backBtnTxt.SetWidescreen(CFG.widescreen); backBtnImg.SetWidescreen(CFG.widescreen); } - GuiButton backBtn(&backBtnImg,&backBtnImg, ALIGN_RIGHT, ALIGN_TOP, -5, 220, &trigA, &btnSoundOver, &btnClick,1); + GuiButton backBtn(&backBtnImg,&backBtnImg, ALIGN_RIGHT, ALIGN_TOP, -5, 220, &trigA, &btnSoundOver, btnClick2,1); backBtn.SetLabel(&backBtnTxt); backBtn.SetTrigger(&trigB); backBtn.SetScale(0.9); @@ -253,9 +255,11 @@ int Theme_Downloader() char THEME_LINK[30] = "http://wii.spiffy360.com/"; /*** Sound Variables ***/ - GuiSound btnSoundOver(button_over_pcm, button_over_pcm_size, SOUND_PCM, Settings.sfxvolume); - GuiSound btnClick(button_click2_pcm, button_click2_pcm_size, SOUND_PCM, Settings.sfxvolume); - GuiSound btnClick1(button_click_pcm, button_click_pcm_size, SOUND_PCM, Settings.sfxvolume); + GuiSound btnSoundOver(button_over_pcm, button_over_pcm_size, Settings.sfxvolume); + // because destroy GuiSound must wait while sound playing is finished, we use a global sound + if(!btnClick2) btnClick2=new GuiSound(button_click2_pcm, button_click2_pcm_size, Settings.sfxvolume); + // GuiSound btnClick(button_click2_pcm, button_click2_pcm_size, Settings.sfxvolume); + GuiSound btnClick1(button_click_pcm, button_click_pcm_size, Settings.sfxvolume); /*** Image Variables ***/ char imgPath[150]; @@ -341,7 +345,7 @@ int Theme_Downloader() backBtnTxt.SetWidescreen(CFG.widescreen); backBtnImg.SetWidescreen(CFG.widescreen); } - GuiButton backBtn(&backBtnImg,&backBtnImg, 2, 3, -180, 400, &trigA, &btnSoundOver, &btnClick,1); + GuiButton backBtn(&backBtnImg,&backBtnImg, 2, 3, -180, 400, &trigA, &btnSoundOver, btnClick2,1); backBtn.SetLabel(&backBtnTxt); backBtn.SetTrigger(&trigB); @@ -354,7 +358,7 @@ int Theme_Downloader() GoLeftBtn.SetPosition(25, -25); GoLeftBtn.SetImage(&GoLeftImg); GoLeftBtn.SetSoundOver(&btnSoundOver); - GoLeftBtn.SetSoundClick(&btnClick); + GoLeftBtn.SetSoundClick(btnClick2); GoLeftBtn.SetEffectGrow(); GoLeftBtn.SetTrigger(&trigA); GoLeftBtn.SetTrigger(&trigL); @@ -366,7 +370,7 @@ int Theme_Downloader() GoRightBtn.SetPosition(-25, -25); GoRightBtn.SetImage(&GoRightImg); GoRightBtn.SetSoundOver(&btnSoundOver); - GoRightBtn.SetSoundClick(&btnClick); + GoRightBtn.SetSoundClick(btnClick2); GoRightBtn.SetEffectGrow(); GoRightBtn.SetTrigger(&trigA); GoRightBtn.SetTrigger(&trigR); diff --git a/source/usbloader/disc.c b/source/usbloader/disc.c index c6084746..40e4ca54 100644 --- a/source/usbloader/disc.c +++ b/source/usbloader/disc.c @@ -234,7 +234,7 @@ s32 Disc_Wait(void) { return 0; } -s32 Disc_SetUSB(u8 *id) { +s32 Disc_SetUSB(const u8 *id) { /* Set USB mode */ return WDVD_SetUSBMode(id); } diff --git a/source/usbloader/disc.h b/source/usbloader/disc.h index 1a09cfef..a06827e9 100644 --- a/source/usbloader/disc.h +++ b/source/usbloader/disc.h @@ -43,7 +43,7 @@ extern "C" { s32 Disc_Open(void); s32 Disc_Wait(void); void __Disc_SetLowMem(void); - s32 Disc_SetUSB(u8 *); + s32 Disc_SetUSB(const u8 *); s32 Disc_ReadHeader(void *); s32 Disc_IsWii(void); s32 Disc_BootPartition(u64, u8, u8, u8, u8, u8, u8, u32); diff --git a/source/usbloader/wdvd.c b/source/usbloader/wdvd.c index 52d602dc..870c1cd2 100644 --- a/source/usbloader/wdvd.c +++ b/source/usbloader/wdvd.c @@ -306,7 +306,7 @@ s32 WDVD_DisableReset(u8 val) { } /** Hermes **/ -s32 WDVD_SetUSBMode(u8 *id) { +s32 WDVD_SetUSBMode(const u8 *id) { s32 ret; memset(inbuf, 0, sizeof(inbuf)); diff --git a/source/usbloader/wdvd.h b/source/usbloader/wdvd.h index 13a3040c..9b3d017a 100644 --- a/source/usbloader/wdvd.h +++ b/source/usbloader/wdvd.h @@ -22,7 +22,7 @@ extern "C" { s32 WDVD_WaitForDisc(void); s32 WDVD_GetCoverStatus(u32 *); s32 WDVD_DisableReset(u8); - s32 WDVD_SetUSBMode(u8 *); + s32 WDVD_SetUSBMode(const u8 *); #ifdef __cplusplus } diff --git a/source/wad/wad.cpp b/source/wad/wad.cpp index ff4efdc3..56f353ed 100644 --- a/source/wad/wad.cpp +++ b/source/wad/wad.cpp @@ -120,12 +120,14 @@ out: s32 Wad_Install(FILE *fp) { //////start the gui shit - GuiWindow promptWindow(472,320); + GuiWindow promptWindow(472,320); promptWindow.SetAlignment(ALIGN_CENTRE, ALIGN_MIDDLE); promptWindow.SetPosition(0, -10); - GuiSound btnSoundOver(button_over_pcm, button_over_pcm_size, SOUND_PCM, Settings.sfxvolume); - GuiSound btnClick(button_click2_pcm, button_click2_pcm_size, SOUND_PCM, Settings.sfxvolume); + GuiSound btnSoundOver(button_over_pcm, button_over_pcm_size, Settings.sfxvolume); + // because destroy GuiSound must wait while sound playing is finished, we use a global sound + if(!btnClick2) btnClick2=new GuiSound(button_click2_pcm, button_click2_pcm_size, Settings.sfxvolume); + // GuiSound btnClick(button_click2_pcm, button_click2_pcm_size, Settings.sfxvolume); char imgPath[100]; snprintf(imgPath, sizeof(imgPath), "%sbutton_dialogue_box.png", CFG.theme_path); @@ -144,7 +146,7 @@ s32 Wad_Install(FILE *fp) if (Settings.wsprompt == yes){ btn1Txt.SetWidescreen(CFG.widescreen); btn1Img.SetWidescreen(CFG.widescreen);} - GuiButton btn1(&btn1Img,&btn1Img, 2, 4, 0, -35, &trigA, &btnSoundOver, &btnClick,1); + GuiButton btn1(&btn1Img,&btn1Img, 2, 4, 0, -35, &trigA, &btnSoundOver, btnClick2,1); btn1.SetLabel(&btn1Txt); btn1.SetState(STATE_SELECTED); @@ -453,8 +455,10 @@ s32 Wad_Uninstall(FILE *fp) promptWindow.SetAlignment(ALIGN_CENTRE, ALIGN_MIDDLE); promptWindow.SetPosition(0, -10); - GuiSound btnSoundOver(button_over_pcm, button_over_pcm_size, SOUND_PCM, Settings.sfxvolume); - GuiSound btnClick(button_click2_pcm, button_click2_pcm_size, SOUND_PCM, Settings.sfxvolume); + GuiSound btnSoundOver(button_over_pcm, button_over_pcm_size, Settings.sfxvolume); + // because destroy GuiSound must wait while sound playing is finished, we use a global sound + if(!btnClick2) btnClick2=new GuiSound(button_click2_pcm, button_click2_pcm_size, Settings.sfxvolume); + // GuiSound btnClick(button_click2_pcm, button_click2_pcm_size, Settings.sfxvolume); char imgPath[100]; snprintf(imgPath, sizeof(imgPath), "%sbutton_dialogue_box.png", CFG.theme_path); @@ -473,7 +477,7 @@ s32 Wad_Uninstall(FILE *fp) if (Settings.wsprompt == yes){ btn1Txt.SetWidescreen(CFG.widescreen); btn1Img.SetWidescreen(CFG.widescreen);} - GuiButton btn1(&btn1Img,&btn1Img, 2, 4, 0, -55, &trigA, &btnSoundOver, &btnClick,1); + GuiButton btn1(&btn1Img,&btn1Img, 2, 4, 0, -55, &trigA, &btnSoundOver, btnClick2,1); btn1.SetLabel(&btn1Txt); btn1.SetState(STATE_SELECTED);