Added menu sounds. See THENMES.md for more details.

This commit is contained in:
Aloshi 2012-10-13 13:29:53 -05:00
parent 20aa6d2a6e
commit ea1a3117a5
17 changed files with 288 additions and 26 deletions

View file

@ -1,7 +1,7 @@
CC=g++
CFLAGS=-c -Wall -I/opt/vc/include -I/opt/vc/include/interface/vcos/pthreads -I/usr/include/freetype2 -I/usr/include/SDL -I/usr/include -D_RPI_
LDFLAGS=-L/opt/vc/lib -lbcm_host -lEGL -lGLESv2 -lfreetype -lSDL -lboost_system -lboost_filesystem -lfreeimage
SRCSOURCES=main.cpp Renderer.cpp Renderer_init.cpp Font.cpp Renderer_draw_gl.cpp GuiComponent.cpp InputManager.cpp SystemData.cpp GameData.cpp FolderData.cpp XMLReader.cpp MathExp.cpp components/GuiGameList.cpp components/GuiInputConfig.cpp components/GuiImage.cpp components/GuiMenu.cpp components/GuiTheme.cpp components/GuiFastSelect.cpp components/GuiBox.cpp pugiXML/pugixml.cpp
LDFLAGS=-L/opt/vc/lib -lbcm_host -lEGL -lGLESv2 -lfreetype -lSDL -lboost_system -lboost_filesystem -lfreeimage -lSDL_mixer
SRCSOURCES=main.cpp Renderer.cpp Renderer_init.cpp Font.cpp Renderer_draw_gl.cpp GuiComponent.cpp InputManager.cpp SystemData.cpp GameData.cpp FolderData.cpp XMLReader.cpp MathExp.cpp components/GuiGameList.cpp components/GuiInputConfig.cpp components/GuiImage.cpp components/GuiMenu.cpp components/GuiTheme.cpp components/GuiFastSelect.cpp components/GuiBox.cpp AudioManager.cpp Sound.cpp pugiXML/pugixml.cpp
SOURCES=$(addprefix src/,$(SRCSOURCES))
OBJECTS=$(SOURCES:.cpp=.o)
EXECUTABLE=emulationstation

View file

@ -1,7 +1,7 @@
CC=g++
CFLAGS=-c -Wall -I/usr/include/freetype2 -I/usr/include/SDL -I/usr/include -D_DESKTOP_ -g
LDFLAGS=-lGL -lfreetype -lSDL -lboost_system -lboost_filesystem -lfreeimage
SRCSOURCES=main.cpp Renderer.cpp Renderer_init.cpp Font.cpp Renderer_draw_gl.cpp GuiComponent.cpp InputManager.cpp SystemData.cpp GameData.cpp FolderData.cpp XMLReader.cpp MathExp.cpp components/GuiGameList.cpp components/GuiInputConfig.cpp components/GuiImage.cpp components/GuiMenu.cpp components/GuiTheme.cpp components/GuiFastSelect.cpp components/GuiBox.cpp pugiXML/pugixml.cpp
LDFLAGS=-lGL -lfreetype -lSDL -lboost_system -lboost_filesystem -lfreeimage -lSDL_mixer
SRCSOURCES=main.cpp Renderer.cpp Renderer_init.cpp Font.cpp Renderer_draw_gl.cpp GuiComponent.cpp InputManager.cpp SystemData.cpp GameData.cpp FolderData.cpp XMLReader.cpp MathExp.cpp components/GuiGameList.cpp components/GuiInputConfig.cpp components/GuiImage.cpp components/GuiMenu.cpp components/GuiTheme.cpp components/GuiFastSelect.cpp components/GuiBox.cpp Sound.cpp AudioManager.cpp pugiXML/pugixml.cpp
SOURCES=$(addprefix src/,$(SRCSOURCES))
OBJECTS=$(SOURCES:.cpp=.o)
EXECUTABLE=emulationstation

View file

@ -98,6 +98,14 @@ The Fast Select box can be themed with these tags:
`<boxCorner>` - path to the "top left corner" image file. It will be flipped for the top right, bottom right, and bottom left corners. ~ and . are expanded.
Audio
=====
Themes can also define menu sounds. Sounds should be in the .wav format.
`<menuScrollSound>` - path to the sound to play when the game list is scrolling.
List of variables
=================

98
src/AudioManager.cpp Normal file
View file

@ -0,0 +1,98 @@
#include "AudioManager.h"
#include "SDL.h"
#include "SDL_mixer.h"
#include <iostream>
#include "Sound.h"
#include <vector>
namespace AudioManager
{
std::vector<Sound*> sSoundVector;
bool sInitialized = false;
void init()
{
int result = Mix_OpenAudio(MIX_DEFAULT_FREQUENCY, AUDIO_S16SYS, 2, 1024);
if(result == -1)
{
std::cerr << "Error initializing AudioManager!\n";
std::cerr << " " << Mix_GetError() << "\n";
return;
}
sInitialized = true;
for(unsigned int i = 0; i < sSoundVector.size(); i++)
{
sSoundVector.at(i)->init();
}
}
void registerSound(Sound* sound)
{
sSoundVector.push_back(sound);
}
void unregisterSound(Sound* sound)
{
for(unsigned int i = 0; i < sSoundVector.size(); i++)
{
if(sSoundVector.at(i) == sound)
{
sSoundVector.erase(sSoundVector.begin() + i);
return;
}
}
std::cerr << "AudioManager Error - tried to unregister a sound that wasn't registered!\n";
}
void test()
{
Mix_Chunk* sound = NULL;
sound = Mix_LoadWAV("test.wav");
if(sound == NULL)
{
std::cerr << "Error loading test sound!\n";
std::cerr << " " << Mix_GetError() << "\n";
return;
}
int channel = -1;
//third argument is play count, -1 = infinite loop, 0 = once
channel = Mix_PlayChannel(-1, sound, 0);
if(channel == -1)
{
std::cerr << "Error playing sound!\n";
std::cerr << " " << Mix_GetError() << "\n";
return;
}
while(Mix_Playing(channel) != 0);
Mix_FreeChunk(sound);
}
void deinit()
{
for(unsigned int i = 0; i < sSoundVector.size(); i++)
{
sSoundVector.at(i)->deinit();
}
Mix_CloseAudio();
sInitialized = false;
}
bool isInitialized()
{
return sInitialized;
}
}

18
src/AudioManager.h Normal file
View file

@ -0,0 +1,18 @@
#ifndef _AUDIOMANAGER_H_
#define _AUDIOMANAGER_H_
class Sound;
namespace AudioManager
{
void registerSound(Sound* sound);
void unregisterSound(Sound* sound);
bool isInitialized();
void init();
void test();
void deinit();
}
#endif

View file

@ -64,11 +64,12 @@ namespace Renderer {
//make sure our font exists
if(!boost::filesystem::exists(fontPath))
{
std::cout << "Default font \"" << fontPath << "\" does not exist! Attempting to default to a system font...\n";
std::cout << "Default font \"" << fontPath << "\" does not exist! Attempting to default to a system font...";
fontPath = "/usr/share/fonts/truetype/ttf-dejavu/DejaVuSans.ttf";
if(!boost::filesystem::exists(fontPath))
{
std::cerr << "System font \"" << fontPath << "\" wasn't found either! Well, you're kind of screwed. Sorry.\n";
return;
}
}

View file

@ -20,9 +20,10 @@ namespace Renderer
{
std::cout << "Creating surface...";
if(SDL_Init(SDL_INIT_VIDEO | SDL_INIT_JOYSTICK) != 0)
if(SDL_Init(SDL_INIT_VIDEO | SDL_INIT_JOYSTICK | SDL_INIT_AUDIO) != 0)
{
std::cerr << "Error initializing SDL!\n";
std::cerr << " " << SDL_GetError() << "\n";
return false;
}

78
src/Sound.cpp Normal file
View file

@ -0,0 +1,78 @@
#include "Sound.h"
#include <iostream>
#include "AudioManager.h"
Sound::Sound(std::string path)
{
mSound = NULL;
AudioManager::registerSound(this);
loadFile(path);
}
Sound::~Sound()
{
deinit();
AudioManager::unregisterSound(this);
}
void Sound::loadFile(std::string path)
{
mPath = path;
init();
}
void Sound::init()
{
if(!AudioManager::isInitialized())
return;
if(mSound != NULL)
deinit();
if(mPath.empty())
return;
mSound = Mix_LoadWAV(mPath.c_str());
if(mSound == NULL)
{
std::cerr << "Error loading sound \"" << mPath << "\"!\n";
std::cerr << " " << Mix_GetError() << "\n";
}
}
void Sound::deinit()
{
if(mSound != NULL)
{
Mix_FreeChunk(mSound);
mSound = NULL;
}
}
void Sound::play()
{
if(mSound == NULL)
return;
mChannel = -1;
mChannel = Mix_PlayChannel(-1, mSound, 0);
if(mChannel == -1)
{
std::cerr << "Error playing sound!\n";
std::cerr << " " << Mix_GetError() << "\n";
}
}
bool Sound::isPlaying()
{
if(mChannel != -1 && Mix_Playing(mChannel))
return true;
else
return false;
}

26
src/Sound.h Normal file
View file

@ -0,0 +1,26 @@
#ifndef _SOUND_H_
#define _SOUND_H_
#include <string>
#include "SDL_mixer.h"
class Sound
{
public:
Sound(std::string path = "");
~Sound();
void init();
void deinit();
void loadFile(std::string path);
void play();
bool isPlaying();
private:
std::string mPath;
int mChannel;
Mix_Chunk* mSound;
};
#endif

View file

@ -6,6 +6,7 @@
#include <stdlib.h>
#include <SDL/SDL_joystick.h>
#include "Renderer.h"
#include "AudioManager.h"
std::vector<SystemData*> SystemData::sSystemVector;
@ -74,6 +75,7 @@ void SystemData::launchGame(GameData* game)
//suspend SDL joystick events (these'll pile up even while something else is running)
SDL_JoystickEventState(0);
AudioManager::deinit();
Renderer::deinit();
std::string command = mLaunchCommand;
@ -88,6 +90,7 @@ void SystemData::launchGame(GameData* game)
std::cout << "...launch terminated!\n";
Renderer::init(0, 0);
AudioManager::init();
//re-enable SDL joystick events
SDL_JoystickEventState(1);

View file

@ -206,6 +206,7 @@ void GuiGameList::updateTheme()
mList->setSelectorColor(mTheme->getSelectorColor());
mList->setSelectedTextColor(mTheme->getSelectedTextColor());
mList->setCentered(mTheme->getListCentered());
mList->setScrollSound(mTheme->getMenuScrollSound());
if(mDetailed)
{

View file

@ -11,7 +11,6 @@
#include "../GameData.h"
#include "../FolderData.h"
//This is where the magic happens - GuiGameList is the parent of almost every graphical element in ES at the moment.
//It has a GuiList child that handles the game list, a GuiTheme that handles the theming system, and a GuiImage for game images.
class GuiGameList : GuiComponent

View file

@ -19,7 +19,7 @@ GuiList<listType>::GuiList(int offsetX, int offsetY, Renderer::FontSize fontsize
mFont = fontsize;
mSelectorColor = 0x000000;
mSelectedTextColorOverride = -1;
mScrollSound = NULL;
mDrawCentered = true;
InputManager::registerComponent(this);
@ -92,13 +92,13 @@ void GuiList<listType>::onInput(InputManager::InputButton button, bool keyDown)
if(button == InputManager::DOWN)
{
mScrollDir = 1;
mSelection++;
scroll();
}
if(button == InputManager::UP)
{
mScrollDir = -1;
mSelection--;
scroll();
}
}else{
if((button == InputManager::DOWN && mScrollDir > 0) || (button == InputManager::UP && mScrollDir < 0))
@ -108,12 +108,6 @@ void GuiList<listType>::onInput(InputManager::InputButton button, bool keyDown)
mScrollDir = 0;
}
}
if(mSelection < 0)
mSelection += mRowVector.size();
if(mSelection >= (int)mRowVector.size())
mSelection -= mRowVector.size();
}
}
@ -141,16 +135,26 @@ void GuiList<listType>::onTick(int deltaTime)
{
mScrollAccumulator -= SCROLLTIME;
mSelection += mScrollDir;
if(mSelection < 0)
mSelection += mRowVector.size();
if(mSelection >= (int)mRowVector.size())
mSelection -= mRowVector.size();
scroll();
}
}
}
}
template <typename listType>
void GuiList<listType>::scroll()
{
mSelection += mScrollDir;
if(mSelection < 0)
mSelection += mRowVector.size();
if(mSelection >= (int)mRowVector.size())
mSelection -= mRowVector.size();
if(mScrollSound)
mScrollSound->play();
}
//list management stuff
template <typename listType>
void GuiList<listType>::addObject(std::string name, listType obj, int color)
@ -249,3 +253,9 @@ void GuiList<listType>::setSelection(int i)
{
mSelection = i;
}
template <typename listType>
void GuiList<listType>::setScrollSound(Sound* sound)
{
mScrollSound = sound;
}

View file

@ -6,6 +6,7 @@
#include "../InputManager.h"
#include <vector>
#include <string>
#include "../Sound.h"
//A graphical list. Supports multiple colors for rows and scrolling.
//TODO - add truncation to text rendering if name exceeds a maximum width (a trailing elipses, perhaps).
@ -34,7 +35,7 @@ public:
void setSelectorColor(int selectorColor);
void setSelectedTextColor(int selectedColor);
void setCentered(bool centered);
void setScrollSound(Sound* sound);
void setTextOffsetX(int textoffsetx);
int getObjectCount();
@ -45,6 +46,8 @@ private:
static const int SCROLLDELAY = 507;
static const int SCROLLTIME = 200;
void scroll(); //helper method, scrolls in whatever direction scrollDir is
int mScrollDir, mScrollAccumulator;
bool mScrolling;
@ -63,6 +66,7 @@ private:
std::vector<ListRow> mRowVector;
int mSelection;
Sound* mScrollSound;
};
#include "GuiList.cpp"

View file

@ -24,6 +24,8 @@ int GuiTheme::getSelectedTextColor() { return mListSelectedColor; }
GuiBoxData GuiTheme::getBoxData() { return mBoxData; }
Sound* GuiTheme::getMenuScrollSound() { return &mMenuScrollSound; }
GuiTheme::GuiTheme(std::string path)
{
setDefaults();
@ -60,6 +62,8 @@ void GuiTheme::setDefaults()
mBoxData.verticalPath = "";
mBoxData.verticalTiled = false;
mBoxData.cornerPath = "";
mMenuScrollSound.loadFile("");
}
void GuiTheme::deleteComponents()
@ -127,10 +131,11 @@ void GuiTheme::readXML(std::string path)
mGameImageOffsetY = strToFloat(root.child("gameImageOffsetY").text().get(), mGameImageOffsetY);
mListTextOffsetX = strToFloat(root.child("listTextOffsetX").text().get(), mListTextOffsetX);
//sounds
mMenuScrollSound.loadFile(root.child("menuScrollSound").text().get());
//recursively create children for all <components> with proper parenting
createComponentChildren(root, this);
//std::cout << "Finished parsing theme.\n";
}
void GuiTheme::createComponentChildren(pugi::xml_node node, GuiComponent* parent)

View file

@ -4,6 +4,7 @@
#include "../GuiComponent.h"
#include "../pugiXML/pugixml.hpp"
#include "GuiBox.h"
#include "../Sound.h"
//This class loads an XML-defined list of GuiComponents.
class GuiTheme : public GuiComponent
@ -29,6 +30,8 @@ public:
float getGameImageOffsetY();
GuiBoxData getBoxData();
Sound* getMenuScrollSound();
private:
void setDefaults();
void deleteComponents();
@ -50,6 +53,8 @@ private:
float mListOffsetX, mGameImageOffsetY, mListTextOffsetX;
GuiBoxData mBoxData;
Sound mMenuScrollSound;
};
#endif

View file

@ -7,6 +7,7 @@
#include <boost/filesystem.hpp>
#include "components/GuiInputConfig.h"
#include <SDL.h>
#include "AudioManager.h"
#include "platform.h"
@ -71,7 +72,7 @@ int main(int argc, char* argv[])
bool running = true;
//the renderer also takes care of setting up SDL for input
//the renderer also takes care of setting up SDL for input and sound
bool renderInit = Renderer::init(width, height);
if(!renderInit)
{
@ -80,9 +81,12 @@ int main(int argc, char* argv[])
}
SDL_JoystickEventState(SDL_ENABLE);
//initialize audio
AudioManager::init();
SDL_JoystickEventState(SDL_ENABLE);
//make sure the config directory exists
std::string home = getenv("HOME");
std::string configDir = home + "/.emulationstation";
@ -171,6 +175,7 @@ int main(int argc, char* argv[])
}
AudioManager::deinit();
Renderer::deleteAll();
Renderer::deinit();
SystemData::deleteSystems();