void SimpleAudioEngine::stopAllEffects() { for (EffectList::iterator it = s_List.begin(); it != s_List.end(); ++it) { it->second->Stop(); } }
void parseEffects() { Parser parser(false, true); parser.readStream(filesystem::FilePackageManager::getInstance().getFile(fileName)); ParserGroup &global = parser.getGlobals(); int groupAmount = global.getSubGroupAmount(); for(int i = 0; i < groupAmount; ++i) { const std::string &name = global.getSubGroupName(i); const ParserGroup &group = global.getSubGroup(i); const ParserGroup &textures = group.getSubGroup("textures"); if(name.empty()) continue; effects.push_back(parseEffectProperties(name, group)); Effect &effect = effects[effects.size() - 1]; int lineCount = textures.getLineCount(); for(int j = 0; j < lineCount; ++j) { const string &texture = textures.getLine(j); addSpawner(effect, manager, texture, storm); } if(lineCount == 0) { Logger::getInstance()->warning("Decal effect with no textures defined"); Logger::getInstance()->warning(name.c_str()); } } }
void SimpleAudioEngine::playPreloadedEffect(int nSoundId) { EffectList::iterator p = s_List.find(nSoundId); if (p != s_List.end()) { p->second.Rewind(); } }
void SimpleAudioEngine::stopEffect(unsigned int nSoundId) { EffectList::iterator p = s_List.find(nSoundId); if (p != s_List.end()) { p->second.Stop(); } }
int getId(const string &name) const { EffectList::const_iterator it = effects.begin(); for(; it != effects.end(); ++it) { if(it->name == name) return it - effects.begin(); } return -1; }
unsigned int SimpleAudioEngine::playEffect(const char* pszFilePath) { unsigned int nRet = _Hash(pszFilePath); preloadEffect(pszFilePath); EffectList::iterator p = s_List.find(nRet); if (p != s_List.end()) { p->second.Rewind(); } return nRet; }
SimpleAudioEngine::~SimpleAudioEngine() { for (EffectList::iterator it = s_List.begin(); it != s_List.end(); ++it) { it->second->Stop(); delete it->second; } s_List.clear(); closeMediaPlayer(s_pBackPlayer); delete s_pBackPlayer; s_pBackPlayer = NULL; }
void QBSoundMac::unloadEffect(const char* filename) { QBSoundLocker locker(&mMutex,"unloadEffect"); if (filename) { unsigned int nRet = _Hash(filename); EffectList::iterator p = effectTrack.find(nRet); if (p != effectTrack.end()) { delete p->second; p->second = NULL; effectTrack.erase(nRet); } } }
void spawn(DecalIdentifier &identifier, int id, const VC3 &position, const QUAT &rotation, const COL &light, bool inBuilding) { assert(id >= 0 && id < int(effects.size())); Effect &effect = effects[id]; if(effect.spawners.empty()) return; float size = effect.sizeMin; float sizeDelta = effect.sizeMax - effect.sizeMin; size += (rand() / float(RAND_MAX)) * sizeDelta; int spawnerIndex = rand() % effect.spawners.size(); DecalSpawner &spawner = *effect.spawners[spawnerIndex]; spawner.setSize(VC2(size, size)); if(!effect.randomRotation) spawner.spawnDecal(identifier, position, rotation, light, inBuilding); else { float angle = rand() % 6000 / 1000.f; QUAT r; r.MakeFromAngles(0, 0, angle); r = r * rotation; spawner.spawnDecal(identifier, position, r, light, inBuilding); } }
void SimpleAudioEngine::preloadEffect(const char* pszFilePath) { int nRet = 0; CCAudioOut* pEffectPlayer = NULL; do { BREAK_IF(! pszFilePath); string strFilePath = fullPathFromRelativePath(pszFilePath); nRet = _Hash(strFilePath.c_str()); BREAK_IF(s_List.end() != s_List.find(nRet)); //AppLog("not find effect, create it..."); if (s_List.size() >= 64) { // get the first effect, and remove it form list //AppLog("effect preload more than 64, delete the first effect"); pEffectPlayer = s_List.begin()->second; pEffectPlayer->Finalize(); s_List.erase(s_List.begin()->first); } if (pEffectPlayer == NULL) pEffectPlayer = new CCAudioOut; pEffectPlayer->Initialize(strFilePath.c_str()); s_List.insert(Effect(nRet, pEffectPlayer)); } while (0); }
void QBSoundMac::preloadEffect(const char* filename) { QBSoundLocker locker(&mMutex,"preloadEffect"); do { if (filename==NULL) break; unsigned int nRet = _Hash(filename); if (effectTrack.end() != effectTrack.find(nRet)) break; effectTrack.insert(make_pair(nRet,new EffectBuffer())); EffectBuffer* buffer = effectTrack[nRet]; if (buffer->load(filename)!=0) { effectTrack.erase(nRet); } } while (0); }
void SimpleAudioEngine::preloadEffect(const char* pszFilePath) { int nRet = 0; do { BREAK_IF(! pszFilePath); nRet = _Hash(pszFilePath); BREAK_IF(s_List.end() != s_List.find(nRet)); s_List.insert(Effect(nRet, MciPlayer())); MciPlayer& player = s_List[nRet]; player.Open(_FullPath(pszFilePath), nRet); BREAK_IF(nRet == player.GetSoundID()); s_List.erase(nRet); nRet = 0; } while (0); }
// for sound effects unsigned int SimpleAudioEngine::playEffect(const char* pszFilePath, bool bLoop/* = false*/) { result r = E_FAILURE; string strFilePath = fullPathFromRelativePath(pszFilePath); unsigned int nRet = _Hash(strFilePath.c_str()); preloadEffect(pszFilePath); EffectList::iterator p = s_List.find(nRet); if (p != s_List.end()) { p->second->SetVolume((int) (s_fEffectsVolume * 99)); int volume = p->second->GetVolume(); if (s_fEffectsVolume > 0.0f && volume == 0) { p->second->SetVolume(1); } if (AUDIOOUT_STATE_PLAYING == p->second->GetState()) { return nRet; // Stop waste a lot of time, so just return. //r = p->second->Stop(); } if (s_fEffectsVolume > 0.0f) { r = p->second->Play(bLoop); } if (IsFailed(r)) { AppLog("play effect fails, error code = %d", r); } } return nRet; }
void QBSoundMac::stopAll() { QBSoundLocker locker(&mMutex,"stopAll"); #ifdef __USE_OGG_VORBIS__ { PlayerList::iterator it = streamTrack.begin(); while(it != streamTrack.end()) { delete (*it).second; ++it; } streamTrack.clear(); } { EffectList::iterator it = effectTrack.begin(); while(it != effectTrack.end()) { delete (*it).second; ++it; } effectTrack.clear(); } #endif return QBSound::stopAll(); }
unsigned int QBSoundMac::playEffect(const char* filename,bool bLoop,float pitch, float pan, float gain) { QBSoundLocker locker(&mMutex,"playEffect"); if (filename) { unsigned int nRet = _Hash(filename); do { if (filename==NULL) break; unsigned int nRet = _Hash(filename); if (effectTrack.end() != effectTrack.find(nRet)) break; effectTrack.insert(make_pair(nRet,new EffectBuffer())); EffectBuffer* buffer = effectTrack[nRet]; if (buffer->load(filename)!=0) { effectTrack.erase(nRet); } } while (0); EffectList::iterator p = effectTrack.find(nRet); if (p != effectTrack.end()) { EffectBuffer* effect = p->second; findPlayer(soundID)->setVolume(gain); findPlayer(soundID)->play((unsigned char*)effect->pcmbuffer,effect->pcmsize); soundID ++; if (soundID > 9999) soundID = 1; } return soundID; } return 0; }
void load(ESMReader &esm) { esm.getHNT(data, "ENDT", 16); effects.load(esm); }
namespace CocosDenshion { typedef map<unsigned int, MciPlayer> EffectList; typedef pair<unsigned int ,MciPlayer> Effect; static SimpleAudioEngine s_SharedEngine; static EffectList s_List; static MciPlayer s_Music; static char s_szRootPath[MAX_PATH]; static DWORD s_dwRootLen; static char s_szFullPath[MAX_PATH]; static const char * _FullPath(const char * szPath); static unsigned int _Hash(const char *key); #define BREAK_IF(cond) if (cond) break; SimpleAudioEngine::SimpleAudioEngine() { } SimpleAudioEngine::~SimpleAudioEngine() { } SimpleAudioEngine* SimpleAudioEngine::sharedEngine() { return &s_SharedEngine; } void SimpleAudioEngine::end() { return; } void SimpleAudioEngine::setResource(const char* pszResPath, const char* pszZipFileName) { } ////////////////////////////////////////////////////////////////////////// // BackgroundMusic ////////////////////////////////////////////////////////////////////////// void SimpleAudioEngine::playBackgroundMusic(const char* pszFilePath, bool bLoop) { if (! pszFilePath) { return; } s_Music.Open(_FullPath(pszFilePath), _Hash(pszFilePath)); s_Music.Play((bLoop) ? -1 : 1); } void SimpleAudioEngine::stopBackgroundMusic(bool bReleaseData) { if (bReleaseData) { s_Music.Close(); } else { s_Music.Stop(); } } void SimpleAudioEngine::pauseBackgroundMusic() { s_Music.Pause(); } void SimpleAudioEngine::resumeBackgroundMusic() { s_Music.Resume(); } void SimpleAudioEngine::rewindBackgroundMusic() { s_Music.Rewind(); } bool SimpleAudioEngine::willPlayBackgroundMusic() { return false; } bool SimpleAudioEngine::isBackgroundMusicPlaying() { return s_Music.IsPlaying(); } ////////////////////////////////////////////////////////////////////////// // effect function ////////////////////////////////////////////////////////////////////////// unsigned int SimpleAudioEngine::playEffect(const char* pszFilePath) { unsigned int nRet = _Hash(pszFilePath); preloadEffect(pszFilePath); EffectList::iterator p = s_List.find(nRet); if (p != s_List.end()) { p->second.Rewind(); } return nRet; } void SimpleAudioEngine::stopEffect(unsigned int nSoundId) { EffectList::iterator p = s_List.find(nSoundId); if (p != s_List.end()) { p->second.Stop(); } } void SimpleAudioEngine::preloadEffect(const char* pszFilePath) { int nRet = 0; do { BREAK_IF(! pszFilePath); nRet = _Hash(pszFilePath); BREAK_IF(s_List.end() != s_List.find(nRet)); s_List.insert(Effect(nRet, MciPlayer())); MciPlayer& player = s_List[nRet]; player.Open(_FullPath(pszFilePath), nRet); BREAK_IF(nRet == player.GetSoundID()); s_List.erase(nRet); nRet = 0; } while (0); } void SimpleAudioEngine::preloadBackgroundMusic(const char* pszFilePath) { } void SimpleAudioEngine::unloadEffect(const char* pszFilePath) { unsigned int nID = _Hash(pszFilePath); s_List.erase(nID); } void SimpleAudioEngine::unloadEffectAll() { s_List.clear(); } ////////////////////////////////////////////////////////////////////////// // volume interface ////////////////////////////////////////////////////////////////////////// int SimpleAudioEngine::getBackgroundMusicVolume() { return 100; } void SimpleAudioEngine::setBackgroundMusicVolume(int volume) { } int SimpleAudioEngine::getEffectsVolume() { return 100; } void SimpleAudioEngine::setEffectsVolume(int volume) { } ////////////////////////////////////////////////////////////////////////// // static function ////////////////////////////////////////////////////////////////////////// const char * _FullPath(const char * szPath) { if (! s_szRootPath[0]) { s_dwRootLen = GetModuleFileName(NULL, s_szRootPath, sizeof(s_szRootPath)); while (--s_dwRootLen) { if ('\\' == s_szRootPath[s_dwRootLen]) { s_szRootPath[s_dwRootLen + 1] = 0; strcpy_s(s_szFullPath, sizeof(s_szFullPath), s_szRootPath); ++s_dwRootLen; break; } } } if (0 != szPath[0] && ':' != szPath[1]) { strcpy_s(s_szFullPath + s_dwRootLen, sizeof(s_szFullPath) - s_dwRootLen, szPath); return s_szFullPath; } else { return szPath; } } unsigned int _Hash(const char *key) { unsigned int len = strlen(key); const char *end=key+len; unsigned int hash; for (hash = 0; key < end; key++) { hash *= 16777619; hash ^= (unsigned int) (unsigned char) toupper(*key); } return (hash); } } // end of namespace CocosDenshion
void SimpleAudioEngine::unloadEffectAll() { s_List.clear(); }
void SimpleAudioEngine::unloadEffect(const char* pszFilePath) { unsigned int nID = _Hash(pszFilePath); s_List.erase(nID); }
void SimpleAudioEngine::unloadEffect(int nSoundId) { s_List.erase(nSoundId); }
namespace CocosDenshion { #define MAX_BUFFER_SIZE 2520 // 840 byte typedef map<unsigned int, CCAudioOut*> EffectList; typedef pair<unsigned int ,CCAudioOut*> Effect; static SimpleAudioEngine *s_pSharedAudioEngine = NULL; static Player *s_pBackPlayer = NULL; static EffectList s_List; static float s_fBackgroundMusicVolume = 1.0f; static float s_fEffectsVolume = 1.0f; static bool s_bWillPlayBackgroundMusic = false; static bool s_bBackgroundMusicPaused = false; static string s_strResourcePath = "/Res/"; static unsigned int _Hash(const char *key) { unsigned int len = strlen(key); const char *end=key+len; unsigned int hash; for (hash = 0; key < end; key++) { hash *= 16777619; hash ^= (unsigned int) (unsigned char) toupper(*key); } return (hash); } static string fullPathFromRelativePath(const char *pszRelativePath) { string strRet=""; int len = strlen(pszRelativePath); if (pszRelativePath == NULL || len <= 0) { return strRet; } if (len > 1 && pszRelativePath[0] == '/') { strRet = pszRelativePath; } else { strRet = s_strResourcePath; strRet += pszRelativePath; } return strRet; } class MyPlayerEventListener : public IPlayerEventListener { public: /** * Notifies that audio/video content was opened asynchronously. * * @param[in] r The cause of the error * @exception E_SUCCESS The method was successful. * @exception E_SYSTEM A system error occurred. * @exception E_CONNECTION_FAILED Network connection failed. * @exception E_UNSUPPORTED_FORMAT The specified format is not supported. * @exception E_UNSUPPORTED_CODEC The specified codec is not supported. * @exception E_OUT_OF_MEMORY Insufficient memory. * @see Player::OpenFile(), Player::OpenUrl(), Player::OpenBuffer() */ virtual void OnPlayerOpened( result r ) { AppLog("OnPlayerOpened result = %d", r); } /** * Notifies that the Player has reached the end of the clip. * */ virtual void OnPlayerEndOfClip(void) { AppLog("OnPlayerEndOfClip"); } /** * Notifies that the position of the audio/video content was moved asynchronously. * * @exception E_SUCCESS The method was successful. * @exception E_SYSTEM A system error occurred. * @see Player::SeekTo() */ virtual void OnPlayerSeekCompleted( result r ) { AppLog("OnPlayerSeekCompleted result = %d", r); } /** * Notifies that streaming data is being buffered. * * @param[in] percent The percentage of buffering completed * @see Player::OpenUrl() */ virtual void OnPlayerBuffering(int percent) { AppLog("OnPlayerBuffering percent = %d%", percent); } /** * Notifies that an error has occurred while the Player is working. * * @param[in] r A player error reason of type ::PlayerErrorReason * @remark While playing streaming media, the player might throw an error like ::PLAYER_ERROR_CONNECTION_LOST @n * ::PLAYER_ERROR_STREAMING_TIMEOUT, ::PLAYER_ERROR_TRANSPORT or ::PLAYER_ERROR_SERVER. @n * If the content includes invalid data, ::PLAYER_ERROR_INVALID_DATA may occur. * @see PlayerErrorReason */ virtual void OnPlayerErrorOccurred( PlayerErrorReason r ) { AppLog("OnPlayerErrorOccurred PlayerErrorReason = %d", r); } /** * Notifies that the Player is being interrupted by a task of higher priority than Player. * */ virtual void OnPlayerInterrupted(void) { AppLog("OnPlayerInterrupted"); //Insert your code here if (s_pBackPlayer->GetState() == PLAYER_STATE_PLAYING) s_pBackPlayer->Pause(); } /** * Notifies that the interrupting Player has been released. * */ virtual void OnPlayerReleased(void) { AppLog("OnPlayerReleased"); //Insert your code here if (s_pBackPlayer->GetState() != PLAYER_STATE_PLAYING) s_pBackPlayer->Play(); } }; static MyPlayerEventListener s_playerListener; static void closeMediaPlayer(Player*& pPlayer) { if (pPlayer != NULL) { PlayerState nowState = pPlayer->GetState(); if( nowState == PLAYER_STATE_PLAYING || nowState == PLAYER_STATE_PAUSED ) { pPlayer->Stop(); pPlayer->Close(); } else if(nowState == PLAYER_STATE_OPENED || nowState == PLAYER_STATE_ENDOFCLIP || nowState == PLAYER_STATE_STOPPED ) { pPlayer->Close(); } } } static bool openMediaPlayer(Player*& pPlayer, const char* pszFilePath) { bool bRet = false; result r = E_FAILURE; do { closeMediaPlayer(pPlayer); if (pPlayer == NULL) { pPlayer = new Player(); r = pPlayer->Construct(s_playerListener, null); if (IsFailed(r)) { AppLog("player construct fails, pszFilePath = %s", pszFilePath); delete pPlayer; pPlayer = NULL; break; } } string strFilePath = fullPathFromRelativePath(pszFilePath); // OpenFile must use synchronous param, for after that it will playing. r = pPlayer->OpenFile(strFilePath.c_str(), false); if (IsFailed(r)) { AppLog("Open (%s) fails\n", strFilePath.c_str()); delete pPlayer; pPlayer = NULL; break; } else { bRet = true; } } while (0); SimpleAudioEngine::sharedEngine()->setBackgroundMusicVolume(s_fBackgroundMusicVolume); return bRet; } SimpleAudioEngine::SimpleAudioEngine() { } SimpleAudioEngine::~SimpleAudioEngine() { for (EffectList::iterator it = s_List.begin(); it != s_List.end(); ++it) { it->second->Stop(); delete it->second; } s_List.clear(); closeMediaPlayer(s_pBackPlayer); delete s_pBackPlayer; s_pBackPlayer = NULL; } SimpleAudioEngine* SimpleAudioEngine::sharedEngine() { if (s_pSharedAudioEngine == NULL) { s_pSharedAudioEngine = new SimpleAudioEngine; } return s_pSharedAudioEngine; } void SimpleAudioEngine::end() { if (s_pSharedAudioEngine) { delete s_pSharedAudioEngine; s_pSharedAudioEngine = NULL; } } void SimpleAudioEngine::setResource(const char* pszZipFileName) { } void SimpleAudioEngine::preloadBackgroundMusic(const char* pszFilePath) { openMediaPlayer(s_pBackPlayer, pszFilePath); } void SimpleAudioEngine::playBackgroundMusic(const char* pszFilePath, bool bLoop) { result r = E_FAILURE; bool bRet = false; bRet = openMediaPlayer(s_pBackPlayer, pszFilePath); if (bRet) { s_pBackPlayer->SetLooping(bLoop); r = s_pBackPlayer->Play(); } } void SimpleAudioEngine::stopBackgroundMusic(bool bReleaseData) { s_bBackgroundMusicPaused = false; if (s_pBackPlayer && PLAYER_STATE_PLAYING == s_pBackPlayer->GetState()) { s_pBackPlayer->Stop(); } } void SimpleAudioEngine::pauseBackgroundMusic() { if (s_pBackPlayer && PLAYER_STATE_PLAYING == s_pBackPlayer->GetState()) { s_bBackgroundMusicPaused = true; s_pBackPlayer->Pause(); } } void SimpleAudioEngine::resumeBackgroundMusic() { if (s_pBackPlayer && s_bBackgroundMusicPaused && PLAYER_STATE_PLAYING != s_pBackPlayer->GetState()) { s_bBackgroundMusicPaused = false; s_pBackPlayer->Play(); } } void SimpleAudioEngine::rewindBackgroundMusic() { stopBackgroundMusic(); if (s_pBackPlayer) { if (PLAYER_STATE_PLAYING != s_pBackPlayer->GetState()) { result r = s_pBackPlayer->Play(); if (IsFailed(r)) { AppLog("ERROR: %s", GetErrorMessage(r)); } } } } bool SimpleAudioEngine::willPlayBackgroundMusic() { return s_bWillPlayBackgroundMusic; } bool SimpleAudioEngine::isBackgroundMusicPlaying() { bool bRet = false; if (s_pBackPlayer) { if (s_pBackPlayer->GetState() == PLAYER_STATE_PLAYING) { bRet = true; } } return bRet; } // properties float SimpleAudioEngine::getBackgroundMusicVolume() { return s_fBackgroundMusicVolume; } void SimpleAudioEngine::setBackgroundMusicVolume(float volume) { if (volume > 1.0f) { volume = 1.0f; } else if (volume < 0.0f) { volume = 0.0f; } if (s_pBackPlayer) { s_pBackPlayer->SetVolume((int) (volume * 99)); if (volume > 0.0f && s_pBackPlayer->GetVolume() == 0) { s_pBackPlayer->SetVolume(1); } } s_fBackgroundMusicVolume = volume; } float SimpleAudioEngine::getEffectsVolume() { return s_fEffectsVolume; } void SimpleAudioEngine::setEffectsVolume(float volume) { if (volume > 1.0f) { volume = 1.0f; } else if (volume < 0.0f) { volume = 0.0f; } s_fEffectsVolume = volume; } // for sound effects unsigned int SimpleAudioEngine::playEffect(const char* pszFilePath, bool bLoop/* = false*/) { result r = E_FAILURE; string strFilePath = fullPathFromRelativePath(pszFilePath); unsigned int nRet = _Hash(strFilePath.c_str()); preloadEffect(pszFilePath); EffectList::iterator p = s_List.find(nRet); if (p != s_List.end()) { p->second->SetVolume((int) (s_fEffectsVolume * 99)); int volume = p->second->GetVolume(); if (s_fEffectsVolume > 0.0f && volume == 0) { p->second->SetVolume(1); } if (AUDIOOUT_STATE_PLAYING == p->second->GetState()) { return nRet; // Stop waste a lot of time, so just return. //r = p->second->Stop(); } if (s_fEffectsVolume > 0.0f) { r = p->second->Play(bLoop); } if (IsFailed(r)) { AppLog("play effect fails, error code = %d", r); } } return nRet; } void SimpleAudioEngine::stopEffect(unsigned int nSoundId) { CCAudioOut*& pPlayer = s_List[nSoundId]; if (pPlayer != NULL) { pPlayer->Stop(); } } void SimpleAudioEngine::pauseEffect(unsigned int nSoundId) { CCAudioOut*& pPlayer = s_List[nSoundId]; if (pPlayer != NULL) { pPlayer->Pause(); } } void SimpleAudioEngine::pauseAllEffects() { for (EffectList::iterator it = s_List.begin(); it != s_List.end(); ++it) { it->second->Pause(); } } void SimpleAudioEngine::resumeEffect(unsigned int nSoundId) { CCAudioOut*& pPlayer = s_List[nSoundId]; if (pPlayer != NULL) { pPlayer->Resume(); } } void SimpleAudioEngine::resumeAllEffects() { for (EffectList::iterator it = s_List.begin(); it != s_List.end(); ++it) { it->second->Resume(); } } void SimpleAudioEngine::stopAllEffects() { for (EffectList::iterator it = s_List.begin(); it != s_List.end(); ++it) { it->second->Stop(); } } void SimpleAudioEngine::preloadEffect(const char* pszFilePath) { int nRet = 0; CCAudioOut* pEffectPlayer = NULL; do { BREAK_IF(! pszFilePath); string strFilePath = fullPathFromRelativePath(pszFilePath); nRet = _Hash(strFilePath.c_str()); BREAK_IF(s_List.end() != s_List.find(nRet)); //AppLog("not find effect, create it..."); if (s_List.size() >= 64) { // get the first effect, and remove it form list //AppLog("effect preload more than 64, delete the first effect"); pEffectPlayer = s_List.begin()->second; pEffectPlayer->Finalize(); s_List.erase(s_List.begin()->first); } if (pEffectPlayer == NULL) pEffectPlayer = new CCAudioOut; pEffectPlayer->Initialize(strFilePath.c_str()); s_List.insert(Effect(nRet, pEffectPlayer)); } while (0); } void SimpleAudioEngine::unloadEffect(const char* pszFilePath) { string strFilePath = fullPathFromRelativePath(pszFilePath); unsigned int nSoundId = _Hash(strFilePath.c_str()); CCAudioOut*& pPlayer = s_List[nSoundId]; pPlayer->Stop(); } } // end of namespace CocosDenshion
float getMaxSize(int id) const { assert(id >= 0 && id < int(effects.size())); return effects[id].sizeMax; }