internal ThemeQueueEntry() { playmode = PsaiPlayMode.regular; themeId = -1; startIntensity = 1.0f; restTimeMillis = 0; holdIntensity = false; }
private void InitMembersAfterSoundtrackHasLoaded() { m_themeQueue.Clear(); m_fadeVoices.Clear(); foreach (Segment segment in m_soundtrack.m_snippets.Values) { segment.audioData.filePathRelativeToProjectDir = m_platformLayer.ConvertFilePathForPlatform(segment.audioData.filePathRelativeToProjectDir); #if !(PSAI_NOLOG) { if (LogLevel.debug <= Logger.Instance.LogLevel) { Logger.Instance.Log("converted path of segment " + segment.Name + " to " + segment.audioData.filePathRelativeToProjectDir, LogLevel.debug); } } #endif } m_soundtrack.UpdateMaxPreBeatMsOfCompatibleMiddleOrBridgeSnippets(); m_lastBasicMood = m_soundtrack.getThemeById(GetLastBasicMoodId()); m_psaiState = PsaiState.silence; m_psaiStateIntended = PsaiState.silence; m_psaiPlayMode = PsaiPlayMode.regular; m_psaiPlayModeIntended = PsaiPlayMode.regular; m_returnToLastBasicMoodFlag = false; m_holdIntensity = false; m_nonInterruptingTriggerOfHighestPriority.themeId = -1; m_soundtrack.BuildAllIndirectionSequences(); }
/** Pops and Plays the next entry in the followingThemeQueue, using the previously stored parameters * for intensity, themeId and SnippetTypes. Removes the themeQueueEntry from the queue afterwards. * @param immediately Play the Theme immediately */ void PopAndPlayNextFollowingTheme(bool immediately) { //boost::recursive_mutex::scoped_lock block(m_pnxLogicMutex); #if !(PSAI_NOLOG) { if (LogLevel.debug <= Logger.Instance.LogLevel) { StringBuilder sb = new StringBuilder(); sb.Append("PopAndPlayNextFollowingTheme() m_themeQueue.size()="); sb.Append(m_themeQueue.Count); sb.Append(" immediately="); sb.Append(immediately); Logger.Instance.Log(sb.ToString(), LogLevel.debug); } } #endif if (getFollowingThemeQueueEntry() != null) { ThemeQueueEntry tqe = getFollowingThemeQueueEntry(); m_psaiPlayModeIntended = tqe.playmode; switch (m_psaiPlayModeIntended) { case PsaiPlayMode.regular: { if (tqe.restTimeMillis == 0) { PlayThemeNowOrAtEndOfCurrentSegment(tqe, immediately); } else { EnterRestMode(tqe.themeId, tqe.themeId); } } break; case PsaiPlayMode.cutScene: { PlayThemeNowOrAtEndOfCurrentSegment(tqe.themeId, tqe.startIntensity, tqe.musicDuration, immediately, tqe.holdIntensity); } break; case PsaiPlayMode.menuMode: { PlayThemeNowOrAtEndOfCurrentSegment(tqe.themeId, tqe.startIntensity, tqe.musicDuration, immediately, tqe.holdIntensity); } break; default: { #if !(PSAI_NOLOG) if (LogLevel.errors <= Logger.Instance.LogLevel) { Logger.Instance.Log("unkown PSAIPLAYMODE !", LogLevel.errors); } #endif } break; } removeFirstFollowingThemeQueueEntry(); } else { #if !(PSAI_NOLOG) { if (LogLevel.errors <= Logger.Instance.LogLevel) { StringBuilder sb = new StringBuilder(); sb.Append("PopAndPlayNextFollowingTheme() - themeQueue is empty!"); Logger.Instance.Log(sb.ToString(), LogLevel.errors); } //AbortWithFatalErrorMessage("FATAL INTERNAL ERROR: PopAndPlayNextFollowingTheme() - themeQueue is empty! !"); } #endif } }
// creates a themequeue-Entry for the theme currently playing and pushes it on the theme queue stack. // If a theme change was imminent, the upcoming theme is stored instead. // Used internally for entering Mode Mode and Cut Scenes void PushEffectiveThemeToThemeQueue(PsaiPlayMode playModeToReturnTo) { #if !(PSAI_NOLOG) { if (LogLevel.debug <= Logger.Instance.LogLevel) { StringBuilder sb = new StringBuilder(); sb.Append("PushEffectiveThemeToThemeQueue() playModeToReturnTo="); sb.Append(playModeToReturnTo); sb.Append(" m_nonInterruptingTriggerCallOfHighestPriority.themeId="); sb.Append(m_nonInterruptingTriggerOfHighestPriority.themeId); sb.Append(" m_currentSegmentPlaying="); if (m_currentSegmentPlaying != null) { sb.Append(m_currentSegmentPlaying.Name); } else { sb.Append("null"); } sb.Append(" m_targetSegment="); if (m_targetSegment != null) { sb.Append(m_targetSegment.Name); } else { sb.Append("null"); } Logger.Instance.Log(sb.ToString(), LogLevel.debug); } } #endif // if we switch from Rest-Mode into MenuMode, we need to remember the remaining milliseconds until we wake up from rest again if (m_psaiState == PsaiState.rest) { int restModeRemainingMillis = GetTimestampMillisElapsedSinceInitialisation() - m_timeStampRestStart; m_timerWakeUpFromRest.Stop(); #if !(PSAI_NOLOG) { if (LogLevel.debug <= Logger.Instance.LogLevel) { Logger.Instance.Log(".. we were in Rest Mode, restModeRemainingMillis=" + restModeRemainingMillis, LogLevel.debug); } } #endif pushThemeToThemeQueue(m_lastBasicMood.id, m_lastBasicMood.intensityAfterRest, 0, true, restModeRemainingMillis, PsaiPlayMode.regular, false); return; } if (m_nonInterruptingTriggerOfHighestPriority.themeId != -1) { // we have received a non-interrupting trigger, so we pack this on the themeQueue. #if !(PSAI_NOLOG) { if (LogLevel.debug <= Logger.Instance.LogLevel) { StringBuilder sb = new StringBuilder(); sb.Append("...m_nonInterruptingTrigger was set, themeId="); sb.Append(m_nonInterruptingTriggerOfHighestPriority.themeId); Logger.Instance.Log(sb.ToString(), LogLevel.debug); } } #endif Theme nonInterruptingTheme = m_soundtrack.getThemeById(m_nonInterruptingTriggerOfHighestPriority.themeId); pushThemeToThemeQueue(nonInterruptingTheme.id, m_nonInterruptingTriggerOfHighestPriority.startIntensity, m_nonInterruptingTriggerOfHighestPriority.musicDuration, false, 0, PsaiPlayMode.regular, false); // clear non-interrupting trigger call, as we would otherwise return this after the first Snippet of the interrupting Theme would have played m_nonInterruptingTriggerOfHighestPriority.themeId = -1; return; } // no trigger is pending, business as usual Segment effectiveSegment = GetEffectiveSegment(); if (effectiveSegment != null) { // Special case: we have already targeted a Snippet of some other theme, or no snippet is playing right now. // This means we have to switch to the target Theme with the maximum music duration if (effectiveSegment == m_targetSegment && m_currentSegmentPlaying == null || (m_targetSegment != null && m_currentSegmentPlaying != null && m_targetSegment.ThemeId != m_currentSegmentPlaying.ThemeId)) { #if !(PSAI_NOLOG) { if (LogLevel.debug <= Logger.Instance.LogLevel) { StringBuilder sb = new StringBuilder(); sb.Append("setting targetSegment.themeId as the following Theme, storing full music duration of themeId="); sb.Append(effectiveSegment.ThemeId); Logger.Instance.Log(sb.ToString(), LogLevel.debug); } } #endif Theme targetTheme = m_soundtrack.getThemeById(m_targetSegment.ThemeId); pushThemeToThemeQueue(m_targetSegment.ThemeId, getUpcomingIntensity(), targetTheme.musicDurationGeneral, false, 0, playModeToReturnTo, m_holdIntensity); } else { // business as usual #if !(PSAI_NOLOG) { if (LogLevel.debug <= Logger.Instance.LogLevel) { StringBuilder sb = new StringBuilder(); sb.Append("pushing themeId of the Effective Segment to Theme Queue, themeId="); sb.Append(effectiveSegment.ThemeId); Logger.Instance.Log(sb.ToString(), LogLevel.debug); } } #endif pushThemeToThemeQueue(effectiveSegment.ThemeId, getCurrentIntensity(), GetRemainingMusicDurationSecondsOfCurrentTheme(), false, 0, playModeToReturnTo, m_holdIntensity); } } else { #if !(PSAI_NOLOG) { if (LogLevel.debug <= Logger.Instance.LogLevel) { StringBuilder sb = new StringBuilder(); sb.Append("not pushing anything to themeQueue. effectiveSnippet="); sb.Append(GetEffectiveSegment()); sb.Append(" m_targetSegment="); sb.Append(m_targetSegment); Logger.Instance.Log(sb.ToString(), LogLevel.debug); } } #endif } }
void SetPlayMode(PsaiPlayMode playMode) { #if !(PSAI_NOLOG) { if (LogLevel.debug <= Logger.Instance.LogLevel) { StringBuilder sb = new StringBuilder(); sb.Append("SetPlayMode() "); sb.Append(playMode); Logger.Instance.Log(sb.ToString(), LogLevel.debug); } } #endif m_psaiPlayMode = playMode; }
internal PsaiResult CutSceneLeave(bool immediately, bool reset) { //boost::recursive_mutex::scoped_lock block(m_pnxLogicMutex); #if !(PSAI_NOLOG) { if (LogLevel.info <= Logger.Instance.LogLevel) { StringBuilder sb = new StringBuilder(); sb.Append("CutSceneLeave() immediately="); sb.Append(immediately); sb.Append(" reset="); sb.Append(reset); Logger.Instance.Log(sb.ToString(), LogLevel.info); } if (LogLevel.debug <= Logger.Instance.LogLevel) { StringBuilder sb2 = new StringBuilder(); sb2.Append(" m_themeQueue.size()="); sb2.Append(m_themeQueue.Count); Logger.Instance.Log(sb2.ToString(), LogLevel.debug); } } #endif if (m_initializationFailure) { #if !(PSAI_NOLOG) { Logger.Instance.Log(LOGMESSAGE_ABORTION_DUE_TO_INITIALIZATION_FAILURE, LogLevel.errors); } #endif return PsaiResult.initialization_error; } ////////////////////////////////////////////////////////////////////////// if (m_psaiPlayMode == PsaiPlayMode.cutScene && m_psaiPlayModeIntended == PsaiPlayMode.cutScene) { if (reset) { m_themeQueue.Clear(); #if !(PSAI_NOLOG) { if (LogLevel.debug <= Logger.Instance.LogLevel) { Logger.Instance.Log("m_themeQueue cleared", LogLevel.debug); } } #endif } if (getFollowingThemeQueueEntry() != null) { m_psaiPlayModeIntended = PsaiPlayMode.regular; PopAndPlayNextFollowingTheme(immediately); return PsaiResult.OK; } else { m_psaiStateIntended = PsaiState.silence; m_psaiState = PsaiState.silence; m_psaiPlayModeIntended = PsaiPlayMode.regular; StopMusic(immediately); return PsaiResult.OK; } } else { #if !(PSAI_NOLOG) if (LogLevel.warnings <= Logger.Instance.LogLevel) { Logger.Instance.Log("CutSceneLeave() ignored - no CutScene was active. Call CutSceneEnter() first!", LogLevel.warnings); } #endif return PsaiResult.commandIgnored; } }
internal PsaiResult CutSceneEnter(int themeId, float intensity) { //boost::recursive_mutex::scoped_lock block(m_pnxLogicMutex); #if !(PSAI_NOLOG) { if (LogLevel.info <= Logger.Instance.LogLevel) { StringBuilder sb = new StringBuilder(); sb.Append("CutSceneEnter(), theme id="); sb.Append(themeId); sb.Append(" , intensity="); sb.Append(intensity); Logger.Instance.Log(sb.ToString(), LogLevel.info); } if (LogLevel.debug <= Logger.Instance.LogLevel) { StringBuilder sb2 = new StringBuilder(); sb2.Append( " m_themeQueue.size()="); sb2.Append(m_themeQueue.Count); Logger.Instance.Log(sb2.ToString(), LogLevel.debug); } } #endif if (m_initializationFailure) { #if !(PSAI_NOLOG) { Logger.Instance.Log(LOGMESSAGE_ABORTION_DUE_TO_INITIALIZATION_FAILURE, LogLevel.errors); } #endif return PsaiResult.initialization_error; } ////////////////////////////////////////////////////////////////////////// switch(m_psaiPlayModeIntended) // we use 'intended' here and not m_psaiPlayMode, so immediate switches back to Cutscene after leaving will be ignored and not cause trouble { case PsaiPlayMode.cutScene: { #if !(PSAI_NOLOG) if (LogLevel.warnings <= Logger.Instance.LogLevel) { Logger.Instance.Log("Cutscene Mode already active - command ignored !", LogLevel.warnings); } #endif return PsaiResult.commandIgnoredCutsceneActive; } //break; case PsaiPlayMode.menuMode: { #if !(PSAI_NOLOG) if (LogLevel.warnings <= Logger.Instance.LogLevel) { Logger.Instance.Log("MenuMode active - command ignored !", LogLevel.warnings); } #endif return PsaiResult.commandIgnoredMenuModeActive; } //break; default: { PushEffectiveThemeToThemeQueue(PsaiPlayMode.regular); Theme cutSceneTheme = m_soundtrack.getThemeById(themeId); SetPlayMode(PsaiPlayMode.cutScene); m_psaiPlayModeIntended = PsaiPlayMode.cutScene; if (cutSceneTheme != null) { PlayThemeNowOrAtEndOfCurrentSegment(themeId, intensity, cutSceneTheme.musicDurationGeneral, true, true); return PsaiResult.OK; } else { PlayThemeNowOrAtEndOfCurrentSegment(m_lastBasicMood.id, intensity, m_lastBasicMood.musicDurationGeneral, true, true); return PsaiResult.unknown_theme; } } //break; } }
internal PsaiResult MenuModeLeave() { // boost::recursive_mutex::scoped_lock block(m_pnxLogicMutex); #if !(PSAI_NOLOG) { if (LogLevel.info <= Logger.Instance.LogLevel) { Logger.Instance.Log("MenuModeLeave", LogLevel.info); } if (LogLevel.debug <= Logger.Instance.LogLevel) { StringBuilder sb = new StringBuilder(); sb.Append(" m_themeQueue.size()="); sb.Append(m_themeQueue.Count); Logger.Instance.Log(sb.ToString(), LogLevel.debug); } } #endif if (m_initializationFailure) { #if !(PSAI_NOLOG) { Logger.Instance.Log(LOGMESSAGE_ABORTION_DUE_TO_INITIALIZATION_FAILURE, LogLevel.errors); } #endif return PsaiResult.initialization_error; } ////////////////////////////////////////////////////////////////////////// if (m_paused) { setPaused(false); } if (m_psaiPlayMode == PsaiPlayMode.menuMode) { if (getFollowingThemeQueueEntry() != null) { PopAndPlayNextFollowingTheme(true); return PsaiResult.OK; } else { m_psaiStateIntended = PsaiState.silence; m_psaiState = PsaiState.silence; SetPlayMode(PsaiPlayMode.regular); m_psaiPlayModeIntended = PsaiPlayMode.regular; StopMusic(true); return PsaiResult.OK; } } else { #if !(PSAI_NOLOG) if (LogLevel.warnings <= Logger.Instance.LogLevel) { Logger.Instance.Log("MenuModeLeave() ignored - MenuMode wasn't active. Call MenuModeEnter() first !", LogLevel.warnings); } #endif return PsaiResult.commandIgnored; } }
internal PsaiResult MenuModeEnter(int menuThemeId, float menuIntensity) { //boost::recursive_mutex::scoped_lock block(m_pnxLogicMutex); #if !(PSAI_NOLOG) { if (LogLevel.info <= Logger.Instance.LogLevel) { StringBuilder sb = new StringBuilder(); sb.Append("entering Menu Mode, menuTheme id="); sb.Append(menuThemeId); sb.Append(" , intensity="); sb.Append(menuIntensity); Logger.Instance.Log(sb.ToString(), LogLevel.info); } if (LogLevel.debug <= Logger.Instance.LogLevel) { StringBuilder sb2 = new StringBuilder(); sb2.Append("MenuModeEnter() m_themeQueue.size()="); sb2.Append(m_themeQueue.Count); Logger.Instance.Log(sb2.ToString(), LogLevel.debug); } } #endif if (m_initializationFailure) { return PsaiResult.initialization_error; } ////////////////////////////////////////////////////////////////////////// if (m_paused) { setPaused(false); } if (m_psaiPlayMode != PsaiPlayMode.menuMode) { // special case: we were leaving a cutscene and the cutscene theme is still playing, // so we don't want to return to the cutscene afterwards if (m_psaiPlayMode == PsaiPlayMode.cutScene && m_psaiPlayModeIntended == PsaiPlayMode.regular) { #if !(PSAI_NOLOG) { if (LogLevel.debug <= Logger.Instance.LogLevel) { StringBuilder sb = new StringBuilder(); sb.Append("special case: Menu Mode entered when we were just returning from the cutscene."); sb.Append(" m_currentTheme->id="); sb.Append(m_effectiveTheme.id); sb.Append(" m_targetSegment="); sb.Append(m_targetSegment); Logger.Instance.Log(sb.ToString(), LogLevel.debug); } } #endif PushEffectiveThemeToThemeQueue(m_psaiPlayModeIntended); } else { PushEffectiveThemeToThemeQueue(m_psaiPlayMode); } Theme menuTheme = m_soundtrack.getThemeById(menuThemeId); if (menuTheme != null) { PlayThemeNowOrAtEndOfCurrentSegment(menuThemeId, menuIntensity, 666, true, true); } else { // TODO: kein Menu Thema wurde gesetzt, d.h. der Menu Mode soll ohne Musik gestartet werden. Hier muss die Musik pausiert und ergo der psai status irgendwie eingefroren werden. Timer killen, timestamps neu berechnen PlayThemeNowOrAtEndOfCurrentSegment(m_lastBasicMood.id, menuIntensity, 666, true, true); // kommt raus sobald die pause funzt } SetPlayMode(PsaiPlayMode.menuMode); m_psaiPlayModeIntended = PsaiPlayMode.menuMode; return PsaiResult.OK; } else { #if !(PSAI_NOLOG) if (LogLevel.warnings <= Logger.Instance.LogLevel) { Logger.Instance.Log("Menu Mode already active", LogLevel.warnings); } #endif return PsaiResult.commandIgnoredMenuModeActive; } }
/* This method will play the target Segment with minimum delay, and set the m_targetSnipet to m_currentSnippet, and m_targetVoice to m_currentVoice. */ void PlayTargetSegmentImmediately() { #if !(PSAI_NOLOG) { if (LogLevel.debug <= Logger.Instance.LogLevel) { StringBuilder sb = new StringBuilder(); sb.Append("PlayTargetSegmentImmediately() m_targetSegmentTypesRequested="); sb.Append(Segment.GetStringFromSegmentSuitabilities(m_targetSegmentSuitabilitiesRequested)); sb.Append(" targetSegment="); sb.Append(m_targetSegment.Name); sb.Append(" id="); sb.Append(m_targetSegment.Id); sb.Append(" m_targetVoice="); sb.Append(m_targetVoice); sb.Append(" themeId="); sb.Append(m_targetSegment.ThemeId); sb.Append(" playbackChannel.Segment=" ); sb.Append(m_playbackChannels[m_targetVoice].Segment.Name); sb.Append(" millisSinceSegmentLoad="); sb.Append( m_playbackChannels[m_targetVoice].GetMillisecondsSinceSegmentLoad()); Logger.Instance.Log(sb.ToString(), LogLevel.debug); } } #endif int snippetPlaybackDelayMillis = 0; if (m_playbackChannels[m_targetVoice].CheckIfSegmentHadEnoughTimeToLoad()) { snippetPlaybackDelayMillis = m_estimatedTimestampOfTargetSnippetPlayback - GetTimestampMillisElapsedSinceInitialisation(); #if !(PSAI_NOLOG) if (LogLevel.debug <= Logger.Instance.LogLevel) { Logger.Instance.Log("Segment had enough time to load. m_estimatedTimestampOfTargetSnippetPlayback=" + m_estimatedTimestampOfTargetSnippetPlayback.ToString(), LogLevel.debug); } #endif } else { int millisUntilLoadingWillHaveFinished = m_playbackChannels[m_targetVoice].GetMillisecondsUntilLoadingWillHaveFinished(); #if !(PSAI_NOLOG) { if (LogLevel.debug <= Logger.Instance.LogLevel) { Logger.Instance.Log("Segment DID NOT have enough time to load! missing milliSeconds=" + millisUntilLoadingWillHaveFinished, LogLevel.debug); } } #endif snippetPlaybackDelayMillis = millisUntilLoadingWillHaveFinished + s_audioLayerMaximumLatencyForPlayingbackPrebufferedSounds; } m_playbackChannels[m_targetVoice].FadeOutVolume = 1.0f; m_playbackChannels[m_targetVoice].ScheduleSegmentPlayback(m_targetSegment, snippetPlaybackDelayMillis); if (m_scheduleFadeoutUponSnippetPlayback) { startFade(m_currentVoiceNumber, PSAI_FADEOUTMILLIS_PLAYIMMEDIATELY, m_targetSegment.audioData.GetPreBeatZoneInMilliseconds() + snippetPlaybackDelayMillis); m_scheduleFadeoutUponSnippetPlayback = false; } m_psaiPlayMode = m_psaiPlayModeIntended; m_currentVoiceNumber = m_targetVoice; m_currentSegmentPlaying = m_targetSegment; m_currentSnippetTypeRequested = m_targetSegmentSuitabilitiesRequested; m_currentSegmentPlaying.Playcount++; //TODO: this should not be increased within menu mode, should it? m_timeStampCurrentSnippetPlaycall = GetTimestampMillisElapsedSinceInitialisation() + snippetPlaybackDelayMillis; // now set the timers for snippet end approaching and snippet end reached int millisUntilUpcomingSnippetEnd = m_targetSegment.audioData.GetFullLengthInMilliseconds() + snippetPlaybackDelayMillis; int millisUntilNextCalculateCall = (int)(millisUntilUpcomingSnippetEnd - m_targetSegment.audioData.GetPostBeatZoneInMilliseconds() - m_targetSegment.MaxPreBeatMsOfCompatibleSnippetsWithinSameTheme - s_audioLayerMaximumLatencyForPlayingBackUnbufferedSounds // deterministic calculation up to here... - 2 * s_updateIntervalMillis); // ... now add some extra headroom for processing time if (millisUntilNextCalculateCall < 0) { #if !(PSAI_NOLOG) { if (LogLevel.warnings <= Logger.Instance.LogLevel) { StringBuilder sb = new StringBuilder(); sb.Append(" psai did not have enough time to evaluate the next Segment in time (missing milliseconds: "); sb.Append(millisUntilNextCalculateCall); sb.Append(")."); sb.Append(" This means that either the main region of Segment '"); sb.Append(m_currentSegmentPlaying.Name); sb.Append("' (ThemeId="); sb.Append(m_currentSegmentPlaying.ThemeId); sb.Append(") is too short, or that the Prebeat region of at least one of its compatible Segments is too long. "); sb.Append("See the 'best practice' section in the psai manual for more information."); Logger.Instance.Log(sb.ToString(), LogLevel.warnings); } } #endif millisUntilNextCalculateCall = 0; } m_targetSegment = null; m_psaiState = PsaiState.playing; if (millisUntilNextCalculateCall < 0) { millisUntilNextCalculateCall = 0; } m_timerSegmentEndApproaching.SetTimer(millisUntilNextCalculateCall, s_updateIntervalMillis); // at the moment the SnippetEndReached Timer only fires for the very last snippet // so it will be extended with every following snippet m_timerSegmentEndReached.SetTimer(millisUntilUpcomingSnippetEnd, 0); #if !(PSAI_NOLOG) { /* if (LogLevel.debug <= Logger.Instance.LogLevel) { StringBuilder sb = new StringBuilder(); sb.Append("m_timer_SegmentEndApproaching should fire in "); sb.Append(millisUntilNextCalculateCall); sb.Append(" ms"); Logger.Instance.Log(sb.ToString(), LogLevel.debug); StringBuilder sb2 = new StringBuilder(); sb2.Append("m_timer_SegmentEndReached should fire in "); sb2.Append(millisUntilUpcomingSnippetEnd); sb2.Append(" ms"); Logger.Instance.Log(sb2.ToString(), LogLevel.debug); } */ } #endif }
/** basic internal function for setting the first theme that will be played as soon as the * current theme's intensity has dropped (or has been set) to zero. This method behaves as a push operation, so the parameter will be * the first theme on the theme queue stack. * @param clearThemeQueue pass true to clear the themeQueue, false to enqueue the followingTheme in the themeQueue * @param restTimeMillis if the theme should start in rest mode, pass the resting millis. 0 otherwise. * @param playMode the playMode that will be entered when the theme is popped. * @param holdIntensity true for holding the intensity at a constant level */ bool pushThemeToThemeQueue(int themeId, float intensity, int musicDuration, bool clearThemeQueue, int restTimeMillis, PsaiPlayMode playMode, bool holdIntensity) { //boost::recursive_mutex::scoped_lock block(m_pnxLogicMutex); #if !(PSAI_NOLOG) { if (LogLevel.info <= Logger.Instance.LogLevel) { StringBuilder sb = new StringBuilder(); sb.Append("setting the Following Theme to "); sb.Append(themeId); if (LogLevel.debug <= Logger.Instance.LogLevel) { sb.Append(" intensity= "); sb.Append(intensity); sb.Append(" clearThemeQueue="); sb.Append(clearThemeQueue); sb.Append(" playmode="); sb.Append(playMode); sb.Append(" holdIntensity="); sb.Append(holdIntensity); sb.Append(" musicDuration="); sb.Append(musicDuration); } Logger.Instance.Log(sb.ToString(), LogLevel.info); } } #endif if (clearThemeQueue) { m_themeQueue.Clear(); } Theme theme = m_soundtrack.getThemeById(themeId); if (theme != null) { ThemeQueueEntry newEntry = new ThemeQueueEntry(); newEntry.themeId = themeId; newEntry.startIntensity = intensity; newEntry.musicDuration = musicDuration; newEntry.restTimeMillis = restTimeMillis; newEntry.playmode = playMode; newEntry.holdIntensity = holdIntensity; #if !(PSAI_NOLOG) { if (LogLevel.debug <= Logger.Instance.LogLevel) { StringBuilder sb = new StringBuilder(); sb.Append(" m_themeQueue.size()="); sb.Append(m_themeQueue.Count); for (int i=0; i<m_themeQueue.Count; i++) { ThemeQueueEntry tmpEntry = m_themeQueue[i]; sb.Append(" ["); sb.Append(i); sb.Append("] themeId="); sb.Append(tmpEntry.themeId); sb.Append(" startIntensity="); sb.Append(tmpEntry.startIntensity); } Logger.Instance.Log(sb.ToString(), LogLevel.debug); } } #endif m_themeQueue.Insert(0, newEntry); m_psaiStateIntended = PsaiState.playing; // in case IntensityZeroHandler() had already been called, we need to reset the psaiStateIntended here return true; } else { return false; } }