예제 #1
0
        public Soundtrack(psai.ProtoBuf_PsaiCoreSoundtrack pbSoundtrack)
            : this()
        {
            for (int i = 0; i < pbSoundtrack.themes.Count; i++)
            {
                psai.ProtoBuf_Theme pbTheme = pbSoundtrack.themes[i];
                Theme tempTheme = new Theme(pbTheme);
                m_themes[tempTheme.id] = tempTheme;
            }

            for (int i = 0; i < pbSoundtrack.snippets.Count; i++)
            {
                psai.ProtoBuf_Snippet pbSnippet = pbSoundtrack.snippets[i];
                Segment tempSnippet = new Segment(pbSnippet);

                m_snippets[tempSnippet.Id] = tempSnippet;

                Theme tmpTheme = m_themes[tempSnippet.ThemeId];
                if (tmpTheme != null)
                {
                    tmpTheme.m_segments.Add(tempSnippet);
                }
                else
                {
                    #if !(PSAI_NOLOG)
                    {
                        if (LogLevel.errors <= Logger.Instance.LogLevel)
                        {
                            string s = "INTERNAL ERROR! could not find Theme for Theme id " + tempSnippet.ThemeId + " of snippet" + tempSnippet.Id;
                            Logger.Instance.Log(s, LogLevel.errors);
                        }                    }
                    #endif
                }
            }
        }
예제 #2
0
 public psai.net.Theme CreatePsaiDotNetVersion()
 {
     psai.net.Theme netTheme = new psai.net.Theme();
     netTheme.id                              = this.Id;
     netTheme.Name                            = this.Name;
     netTheme.themeType                       = (psai.net.ThemeType) this.ThemeTypeInt;
     netTheme.intensityAfterRest              = this.IntensityAfterRest;
     netTheme.musicDurationGeneral            = this.MusicPhaseSecondsGeneral;
     netTheme.musicDurationAfterRest          = this.MusicPhaseSecondsAfterRest;
     netTheme.restSecondsMin                  = this.RestSecondsMin;
     netTheme.restSecondsMax                  = this.RestSecondsMax;
     netTheme.priority                        = this.Priority;
     netTheme.weightings.switchGroups         = this.WeightingSwitchGroups;
     netTheme.weightings.intensityVsVariety   = this.WeightingIntensityVsVariance;
     netTheme.weightings.lowPlaycountVsRandom = this.WeightingLowPlaycountVsRandom;
     return(netTheme);
 }
예제 #3
0
 public psai.net.Theme CreatePsaiDotNetVersion()
 {
     psai.net.Theme netTheme = new psai.net.Theme();
     netTheme.id = this.Id;
     netTheme.Name = this.Name;
     netTheme.themeType = (psai.net.ThemeType)this.ThemeTypeInt;
     netTheme.intensityAfterRest = this.IntensityAfterRest;
     netTheme.musicDurationGeneral = this.MusicPhaseSecondsGeneral;
     netTheme.musicDurationAfterRest = this.MusicPhaseSecondsAfterRest;
     netTheme.restSecondsMin = this.RestSecondsMin;
     netTheme.restSecondsMax = this.RestSecondsMax;
     netTheme.priority = this.Priority;
     netTheme.weightings.switchGroups = this.WeightingSwitchGroups;
     netTheme.weightings.intensityVsVariety = this.WeightingIntensityVsVariance;
     netTheme.weightings.lowPlaycountVsRandom = this.WeightingLowPlaycountVsRandom;
     return netTheme;
 }
예제 #4
0
        /** returns the id of the theme set as baseTheme. 
	    * If no baseTheme has been triggered yet, the baseTheme with the lowest id is returned, or -1 if no base theme was found at all.
	    */
        internal int GetLastBasicMoodId()
	    {
		    if (m_lastBasicMood != null)
		    {
			    return m_lastBasicMood.id;
		    }
		    else
		    {
                foreach(Theme tmpThema in m_soundtrack.m_themes.Values)
                {
                    if (tmpThema.themeType == ThemeType.basicMood)
                    {
                        m_lastBasicMood = tmpThema;
                        return tmpThema.id;
                    }
                }
                return -1;
            }		
	    }
예제 #5
0
        void SetThemeAsLastBasicMood(Theme latestBasicMood)
	    {
		    if (latestBasicMood != null)
		    {
			    #if !(PSAI_NOLOG)
			    {
                    if (m_lastBasicMood == null || (m_lastBasicMood != null && m_lastBasicMood!= latestBasicMood))
                    if (LogLevel.info <= Logger.Instance.LogLevel)
                    {
                    	Logger.Instance.Log( "Setting Theme " + latestBasicMood.id + " as the Last Basic Mood", LogLevel.info);
                    }
			    }
			    #endif

			    m_lastBasicMood = latestBasicMood;
		    }
		    else
		    {
                #if !(PSAI_NOLOG)
                {
                    if (LogLevel.warnings <= Logger.Instance.LogLevel)
                    {
                        Logger.Instance.Log("SetThemeAsLatestBasicMood(): invalid theme argument ! ", LogLevel.warnings);
                    }
                }
                #endif
            }
	    }
예제 #6
0
        private void EnterSilenceMode()
	    {
		    // enter silence mode
		   #if !(PSAI_NOLOG)
		    if (LogLevel.info <= Logger.Instance.LogLevel)
		    {
		    	Logger.Instance.Log("entering Silence Mode", LogLevel.info);
		    }
		   #endif
            
            m_timerStartSnippetPlayback.Stop();
            m_timerSegmentEndApproaching.Stop();

            m_targetSegment = null;
            m_effectiveTheme = null;
            m_scheduleFadeoutUponSnippetPlayback = false;

            m_psaiStateIntended = PsaiState.silence;
            m_psaiState = PsaiState.silence;        
	    }
예제 #7
0
        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();
        }
예제 #8
0
        internal Logik()
        {
            #if PSAI_STANDALONE
                m_platformLayer = new PlatformLayerStandalone(this);
            #else
                m_platformLayer = new PlatformLayerUnity();
            #endif

            m_platformLayer.Initialize();

            m_soundtrack = new Soundtrack();
            m_themeQueue = new List<ThemeQueueEntry>();                        
            m_fadeVoices = new List<FadeData>();

            for (int i = 0; i < PSAI_CHANNEL_COUNT; i++)
            {
                m_playbackChannels[i] = new PlaybackChannel();
            }


            m_hilightVoiceIndex = -1;
            m_lastRegularVoiceNumberReturned = -1;
            m_currentVoiceNumber = -1;
            m_targetVoice = -1;

            m_psaiMasterVolume = 1.0f;  		   

            m_effectiveTheme = null;
            m_currentSegmentPlaying = null;
            m_currentSnippetTypeRequested = 0; 
            m_targetSegment = null;
            m_targetSegmentSuitabilitiesRequested = 0;

            m_psaiState = PsaiState.notready;
            m_psaiStateIntended = PsaiState.notready;

            m_paused = false;
            
            m_fullVersionString = "psai Version " + PSAI_VERSION;
            #if !(PSAI_NOLOG)
                Logger.Instance.LogLevel = LogLevel.info;
                Logger.Instance.Log(m_fullVersionString, LogLevel.info);
            #endif


            s_instance = this;
        }
예제 #9
0
        Segment GetBestStartSegmentForTheme_internal(Theme theme, float intensity)
	    {
		    //boost::recursive_mutex::scoped_lock block(m_pnxLogicMutex);

		    float maxDeltaIntensity = 0.0f;
		    int minAbgespielt = 0;
		    int maxAbgespielt = 0;

		    // Vergleichsliste aufbauen
		    List<Follower> segmentList = new List<Follower>();

		    int teilstueckeCount = theme.m_segments.Count;

		    for (int i=0; i < teilstueckeCount; i++)
		    {
			    Segment tempTeil = theme.m_segments[i];

			    if (tempTeil != null)
			    {
				    if (  ((int)SegmentSuitability.start & tempTeil.SnippetTypeBitfield ) > 0 )
				    {
					    if (i==0)
					    {
						    minAbgespielt = tempTeil.Playcount;
					    }
					    else
					    {
						    if (tempTeil.Playcount < minAbgespielt) 
							    minAbgespielt = tempTeil.Playcount;
					    }

					    if (tempTeil.Playcount > maxAbgespielt) 
						    maxAbgespielt = tempTeil.Playcount;


					    float tDeltaIntensity = intensity - tempTeil.Intensity;

					    if (tDeltaIntensity < 0.0f) 
						    tDeltaIntensity = tDeltaIntensity * -1.0f;

					    if (tDeltaIntensity > maxDeltaIntensity) 
						    maxDeltaIntensity = tDeltaIntensity;

					    // kreiere eine snippetType Nachfolger
					    Follower vorfolger = new Follower();
					    vorfolger.snippetId = tempTeil.Id;
                        vorfolger.compatibility = 1.0f;                 // compatiblity is ignored for Start-Segments and therefore set to 1.0f
					    segmentList.Add(vorfolger); 
				    }
			    }
			    else
			    {
				    #if !(PSAI_NOLOG)
				    {
                        if (LogLevel.errors <= Logger.Instance.LogLevel)
                        {
	                        StringBuilder sb = new StringBuilder();
	                        sb.Append("INTERNAL ERROR ! GetBestStartSegmentForTheme_internal() - a Segment with id ");
	                        sb.Append(tempTeil.Id);
	                        sb.Append(" could not be found!");
	                        Logger.Instance.Log(sb.ToString(), LogLevel.errors);
                        }
				    }
				    #endif
			    }
		    }

		    Weighting weighting = theme.weightings;

		    return ChooseBestSegmentFromList(segmentList, weighting, intensity, maxAbgespielt, minAbgespielt, maxDeltaIntensity);
	    }
예제 #10
0
        PsaiResult HandleNonInterruptingTriggerCall(Theme argTheme, float intensity, int musicDuration)
        {
            #if !(PSAI_NOLOG)
            {            
                if (LogLevel.debug <= Logger.Instance.LogLevel)
                {
	                StringBuilder sb = new StringBuilder();
	                sb.Append("HandleNonInterruptingTriggerCall() argTheme=");
	                sb.Append(argTheme.Name);
	                sb.Append("  intensity=");
	                sb.Append(intensity);
	                sb.Append("  musicDuration=");
	                sb.Append(musicDuration);
	                Logger.Instance.Log(sb.ToString(), LogLevel.debug);
                }
            }
            #endif


            bool updateTqe = false;
            if (m_nonInterruptingTriggerOfHighestPriority.themeId != -1)
            {                
                m_nonInterruptingTriggerOfHighestPriority.themeId = -1;
                updateTqe = true;

                /*
                #if !(PSAI_NOLOG)
                {
                    if (LogLevel.debug <= Logger.Instance.LogLevel)
                    {
	                    StringBuilder sb = new StringBuilder();
	                    sb.Append("previouslyTriggeredTheme was null");
	                    Logger.Instance.Log(sb.ToString(), LogLevel.debug);
                    }
                }
                #endif
                */
            }
            else
            {
                // check if the trigger call differs from the last one
                if ( m_nonInterruptingTriggerOfHighestPriority.themeId != argTheme.id         ||
                    m_nonInterruptingTriggerOfHighestPriority.startIntensity != intensity
                    )
                {
                        #if !(PSAI_NOLOG)
                        {
                            /*
                            if (LogLevel.debug <= Logger.Instance.LogLevel)
                            {
	                            StringBuilder sb = new StringBuilder();
	                            sb.Append("differing trigger -> update");
	                            Logger.Instance.Log(sb.ToString(), LogLevel.debug);
                            }
                             */
                        }
                        #endif

                    updateTqe = true;
                }
            }

            if (updateTqe)
            {
                m_nonInterruptingTriggerOfHighestPriority.themeId = argTheme.id;
                m_nonInterruptingTriggerOfHighestPriority.startIntensity = intensity;
                m_nonInterruptingTriggerOfHighestPriority.musicDuration = musicDuration;
                m_psaiStateIntended = PsaiState.playing;
                return PsaiResult.OK;
            }
            else
            {
                #if !(PSAI_NOLOG)
                    if (LogLevel.debug <= Logger.Instance.LogLevel)
                    {
                    	Logger.Instance.Log("... no update necessary", LogLevel.debug);
                    }
                #endif

                return PsaiResult.OK;    
            }
        }
예제 #11
0
        /* sets the psaiState to PSAISTATE_REST, where no music is played for a period defined in the themes.psai file.
	    * param themeId the theme that will affect the duration of the rest, and will be played automatically when the rest is over.
	    * param restMillis the milliseconds to rest. Pass 0 to have the resting millis calculated based on the authored data.
	    */
	    void EnterRestMode(int themeIdToWakeUpWith, int themeIdToUseForRestingTimeCalculation)
	    {
		    //boost::recursive_mutex::scoped_lock block(m_pnxLogicMutex);

		    #if !(PSAI_NOLOG)
            {
                if (LogLevel.info <= Logger.Instance.LogLevel)
                {
	                StringBuilder sb = new StringBuilder();
	                sb.Append("--- Entering rest mode. Will wake up with Theme ");
	                sb.Append(themeIdToWakeUpWith);
	                Logger.Instance.Log(sb.ToString(), LogLevel.info);
                }
            }
		    #endif

		    m_psaiState = PsaiState.rest;
            m_holdIntensity = false;
            m_timerStartSnippetPlayback.Stop();     // may be necessary if we have been fading out immediately
            m_timerSegmentEndApproaching.Stop();    // may be necessary if we have been fading out immediately
            m_timerWakeUpFromRest.Stop();

            m_effectiveTheme = m_soundtrack.getThemeById(themeIdToWakeUpWith);      // the effective Theme is also valid during Rest Mode

		    if (m_effectiveTheme != null)
		    {
                int millisTimerRest = 0;

                if (m_restModeSecondsOverride > 0)
                {

          		    #if !(PSAI_NOLOG)
                    {
                        if (LogLevel.info <= Logger.Instance.LogLevel)
                        {
	                        StringBuilder sb = new StringBuilder();
	                        sb.Append("--- resting time is based on override values.");
	                        Logger.Instance.Log(sb.ToString(), LogLevel.info);
                        }
                    }
		            #endif

                    millisTimerRest = m_restModeSecondsOverride;
                    m_restModeSecondsOverride = -1;
                }
                else
                {
                    Theme themeRest = m_soundtrack.getThemeById(themeIdToUseForRestingTimeCalculation);
                    if (themeRest != null)
                    {
                        #if !(PSAI_NOLOG)
                        {
                            if (LogLevel.info <= Logger.Instance.LogLevel)
                            {
	                            StringBuilder sb = new StringBuilder();
	                            sb.Append("--- resting time is based on Theme ");
                                sb.Append(themeRest.Name);
	                            Logger.Instance.Log(sb.ToString(), LogLevel.info);
                            }
                        }
                        #endif

                        millisTimerRest = GetRandomInt(themeRest.restSecondsMin, themeRest.restSecondsMax) * 1000;
                    }
                    else
                    {
                        #if !(PSAI_NOLOG)
                        {
                            if (LogLevel.warnings <= Logger.Instance.LogLevel)
                            {
                                StringBuilder sb = new StringBuilder();
                                sb.Append("--- resting time is based on Theme ");
                                sb.Append(m_effectiveTheme.Name);
                                sb.Append("(themeIdToUseForRestingTimeCalculation was not found: ");
                                sb.Append(themeIdToUseForRestingTimeCalculation);
                                sb.Append(" )");
                                Logger.Instance.Log(sb.ToString(), LogLevel.warnings);
                            }
                        }
                        #endif

                        millisTimerRest = GetRandomInt(m_effectiveTheme.restSecondsMin, m_effectiveTheme.restSecondsMax) * 1000;
                    }
                }


			    if (millisTimerRest > 0)
			    {
				    m_timeStampRestStart = GetTimestampMillisElapsedSinceInitialisation();

				    #if !(PSAI_NOLOG)
				    {
                        if (LogLevel.info <= Logger.Instance.LogLevel)
                        {
	                        StringBuilder sb = new StringBuilder();
	                        sb.Append("...resting for ");
						    sb.Append(millisTimerRest);
	                        sb.Append(" ms");
	                        Logger.Instance.Log(sb.ToString(), LogLevel.info);
                        }
				    }
				    #endif

                    m_timerWakeUpFromRest.SetTimer(millisTimerRest, 0);				    
			    }
			    else
			    {
				    #if !(PSAI_NOLOG)
				    {
                        if (LogLevel.info <= Logger.Instance.LogLevel)
                        {
                        	Logger.Instance.Log("resting time is zero, starting again immediately.", LogLevel.info);
                        }
				    }
				    #endif

				    WakeUpFromRestHandler();
			    }
		    }
		    else
		    {
			    #if !(PSAI_NOLOG)
			    {
                    if (LogLevel.errors <= Logger.Instance.LogLevel)
                    {
                    	Logger.Instance.Log("can't go to rest because Theme wasn't found!", LogLevel.errors);
                    }
			    }
			    #endif
		    }
        }
예제 #12
0
        /** internal function to initiate the playback of a theme.
	    * @param themeId     id of the theme to be played 
	    * @param intensity   the desired intensity level [0.0f ... 1.0f]
	    * @param immediately true: play instantly   false: play at end of current snippet
	    * @param SnippetType
	    * @param recalculateIntensitySlope pass true if the intensity slope needs to be reinitialized to the full musical period as defined in the authoring software.
	    * @param holdIntensity pass true if the intensity should be held on a constant level, false otherwise (default is false)
	    * @return PsaiResult.OK ok, theme will be played
	    *		PSAI_INFO_TRIGGER_DENIED trigger was denied as a theme transition is not guaranteed due to missing snippet transitions, and error handling was set to DENY_TRIGGER
	    *		PSAI_ERR_ESSENTIAL_SNIPPET_MISSING a transition could not be achieved because there was no compatible follower to the current snippet, and error handling was set to ABORT or STOP_MUSIC
	    *		
	    */
	    PsaiResult PlayThemeNowOrAtEndOfCurrentSegment(int themeId, float intensity, int musicDuration, bool immediately, bool holdIntensity)
	    {
		    #if !(PSAI_NOLOG)
		    {
                if (LogLevel.debug <= Logger.Instance.LogLevel)
                {
	                Theme theme = m_soundtrack.getThemeById(themeId);
	
	                StringBuilder sb = new StringBuilder();
	                sb.Append("PlayThemeNowOrAtEndOfCurrentSegment()  themeId=");
	                sb.Append(themeId);
	
	                if (theme == null)
	                {
	                    sb.Append("THEME NOT FOUND!");
	                }
	                else
	                {
	                    sb.Append(" [");
	                    sb.Append(theme.Name);
	                    sb.Append("]  themeType=");
	                    sb.Append(theme.themeType);
	                }
	
	                sb.Append( " intensity=");
	                sb.Append(intensity);
	                sb.Append(" immediately=");
	                sb.Append(immediately);
	                sb.Append(" holdIntensity=");
	                sb.Append(holdIntensity);
	                sb.Append(" musicDuration=");
	                sb.Append(musicDuration);
	                sb.Append(" m_currentSegmentPlaying=");
	                sb.Append(m_currentSegmentPlaying);
	
	                Logger.Instance.Log(sb.ToString(), LogLevel.debug);
                }
		    }
		    #endif

            SetCurrentIntensityAndMusicDuration(intensity, musicDuration, true);

            m_psaiStateIntended = PsaiState.playing;
            m_heldIntensity = intensity;

		    // if we're interrupting rest mode, kill the rest wake up timer		    
            if (m_psaiState == PsaiState.rest)
		    {
                m_timerWakeUpFromRest.Stop();
		    }


            

            // choice of Segment Suitability:
            // * Use Start Segments:
            //      1. when playing out of silence
            //      2. if a pure END-Segment is currently playing
            // * Use Middle Segments when staying within the current Theme.
            // * Use Bridge or Middle Segments when transitioning to another Theme.            
            m_targetSegmentSuitabilitiesRequested = (int)SegmentSuitability.start;

            if (m_psaiState == PsaiState.playing)
            {               
                if (m_currentSegmentPlaying != null)
                {
                    if (m_currentSegmentPlaying.IsUsableOnlyAs(SegmentSuitability.end))
                    {
                        m_targetSegmentSuitabilitiesRequested = (int)SegmentSuitability.start;
                    }
                    else
                    {
                        if (getEffectiveThemeId() == themeId)
                        {
                            // we stay within the same Theme, so choose a MIDDLE Segment
                            // NOTE: this may only happen if we return from the Menu or a CutScene to the same Theme. Otherwise,
                            // PlayThemeNowOrAtEndOfCurrentSegment should not be called explicitly
                            m_targetSegmentSuitabilitiesRequested = (int)SegmentSuitability.middle;
                        }
                        else
                        {
                            // upon Theme changes we play BRIDGE or MIDDLE Segments
                            m_targetSegmentSuitabilitiesRequested = SNIPPET_TYPE_MIDDLE_OR_BRIDGE;
                        }
                    }
                }
            }

            m_effectiveTheme = m_soundtrack.getThemeById(themeId);

            Segment targetSnippet;
            if ((m_targetSegmentSuitabilitiesRequested & (int)SegmentSuitability.start) > 0 || GetEffectiveSegment() == null)
            {
                targetSnippet = GetBestStartSegmentForTheme(themeId, intensity);
            }
            else
            {
                targetSnippet = GetBestCompatibleSegment(GetEffectiveSegment(), themeId, intensity, m_targetSegmentSuitabilitiesRequested);
            }


		    //////////////////////////////////////////////////////////////////////////
		    // no compatible Segment could be found !
		    //////////////////////////////////////////////////////////////////////////
		    if (targetSnippet == null)
		    {
				#if !(PSAI_NOLOG)
				{
                    Logger.Instance.Log("essential Segment could not be found! Trying to substitute...", LogLevel.errors);
				}
				#endif

				targetSnippet = substituteSegment(themeId);

				if (targetSnippet == null)
				{
					#if !(PSAI_NOLOG)
					{
                        Logger.Instance.Log("failed to substitute Segment. Stopping music.", LogLevel.errors);
					}
					#endif

					StopMusic(true);
					return PsaiResult.essential_segment_missing;
				}
		    }

		    // ////////////////////////////////////////////////
		    // at this point, the target Segment has to be set! (internal error otherwise)
		    // ////////////////////////////////////////////////

		    m_holdIntensity = holdIntensity;
            
            // starting a Theme immediately when any other Theme is already playing should result in
            // fading out that other Theme.
            if (immediately && GetEffectiveSegment() != null)
            {
                m_scheduleFadeoutUponSnippetPlayback = true;
            }

		    if (targetSnippet != null)
		    {
                return PlaySegment(targetSnippet, immediately);	
		    }
		    else
		    {
			    #if !(PSAI_NOLOG)
			    {
                    Logger.Instance.Log("fatal internal error! entered code section in PlayTheme that is supposed to be unreachable!", LogLevel.errors);
			    }
			    #endif

			    return PsaiResult.internal_error;
		    }
	    }
예제 #13
0
        /**
	    *                                                                      
	    * @return PSAI_OK ok hightlight is being played
		    PSAI_INFO_TRIGGER_IGNORED_LOW_PRIORITY  trigger ignored, because a highlight of a higher priority is currently being played.
		    PSAI_ERR_ESSENTIAL_SEGMENT_MISSING  ignored, because no compatible Segment could be found.			
	    */
	    PsaiResult startHighlight(Theme highlightTheme)
	    {
		    //boost::recursive_mutex::scoped_lock blockieren(m_pnxLogicMutex);

		    #if !(PSAI_NOLOG)
			    if (LogLevel.debug <= Logger.Instance.LogLevel)
			    {
			    	Logger.Instance.Log("startHighlight()", LogLevel.debug);
			    }
		    #endif


		    // Highlights are always SNIPPET_TYPE_MIDDLE
		    if (highlightTheme.m_segments.Count > 0)
		    {

                // deine omma

			    Segment tempTeil;

                if (m_currentSegmentPlaying != null)
                {
                    tempTeil = GetBestCompatibleSegment(m_currentSegmentPlaying, highlightTheme.id, getCurrentIntensity(), (int)SegmentSuitability.whatever);
                }
			    else 
			    {
                    int randomSegmentIndex = GetRandomInt(0, highlightTheme.m_segments.Count);  // note: GetRandomInt will never return the max value.
                    tempTeil = m_soundtrack.GetSegmentById(highlightTheme.m_segments[randomSegmentIndex].Id);
			    }

			    if (tempTeil != null)
			    {	
				    //PsaiResult psaiResult;

                    // TODO: check if we need to fade out highlights

				    // is currently a highlight playing, has it a lower priority and is in need of a fade?
                    /*
				    bool playing = false;
				    if (m_hilightVoiceIndex > -1)
				    {
					    psaiResult = m_audioPlaybackLayer->isPlaying(m_hilightVoiceIndex, &playing);
					    if (playing) 
					    {
						    if ( m_priorityOfCurrentHighlight > highlightTheme->priority) 
							    return PSAI_RC_TRIGGER_IGNORED_LOW_PRIORITY;	// no need to do anything further
						    else 
							    startFade(m_hilightVoiceIndex, PSAI_FADEOUTMILLIS_HIGHLIGHT_INTERRUPTED);
					    }
				    }
                     */

                    PlaySegmentLayeredAndImmediately(tempTeil);

                    tempTeil.Playcount++;

				    return PsaiResult.OK;
			    }
			    else
			    {
				    #if !(PSAI_NOLOG)
				    {
                        if (LogLevel.warnings <= Logger.Instance.LogLevel)
                        {
	                        StringBuilder sb = new StringBuilder();
	                        sb.Append("the triggered Highlight Layer ");
	                        sb.Append(highlightTheme.id);
	                        sb.Append(" does not contain a compatible Highlight Segment.");
	                        if (m_currentSegmentPlaying != null)
	                        {
	                            sb.Append(" Current Segment playing:");
	                            sb.Append(m_currentSegmentPlaying.Name);
	                        }
	                        else
	                        {
	                            sb.Append(" (No Segment is currently playing.)");
	                        }
	                        Logger.Instance.Log(sb.ToString(), LogLevel.warnings);
                        }
				    }
				    #endif

				    return PsaiResult.essential_segment_missing;
			    }
		    }
		    else
		    {
			    #if !(PSAI_NOLOG)
			    {
                    if (LogLevel.warnings <= Logger.Instance.LogLevel)
                    {
	                    StringBuilder sb = new StringBuilder();
	                    sb.Append("the triggered Highlight Theme ");
	                    sb.Append(highlightTheme.id);
	                    sb.Append(" does not contain any Segments.");
	                    Logger.Instance.Log(sb.ToString(), LogLevel.warnings);
                    }
			    }
			    #endif

			    return PsaiResult.essential_segment_missing;
		    }
	    }
예제 #14
0
        internal PsaiResult TriggerMusicTheme(Theme argTheme, float argIntensity, int argMusicDuration)
        {
            if (m_initializationFailure)
            {
                #if !(PSAI_NOLOG)
                {
                    if (LogLevel.errors <= Logger.Instance.LogLevel)
                    {
                    	Logger.Instance.Log(LOGMESSAGE_ABORTION_DUE_TO_INITIALIZATION_FAILURE, LogLevel.errors);
                    }
                }
                #endif

                return PsaiResult.initialization_error;
            }

		    //////////////////////////////////////////////////////////////////////////

            if (m_paused)
            {
                setPaused(false);
            }

            Segment effectiveSegment = GetEffectiveSegment();

            // special treatment for Highlights
            if (argTheme.themeType == ThemeType.highlightLayer)
            {
   				if (CheckIfAnyThemeIsCurrentlyPlaying() == true)
				{
					if (m_effectiveTheme != null && effectiveSegment != null && effectiveSegment.CheckIfAtLeastOneDirectTransitionOrLayeringIsPossible(m_soundtrack, argTheme.id) == false)
					{
						#if !(PSAI_NOLOG)
						{
                            Logger.Instance.Log(LOGMESSAGE_TRIGGER_DENIED, LogLevel.warnings);
						}
						#endif	
						return PsaiResult.triggerDenied;
					};
				}

				return startHighlight(argTheme);
            }


		    // return immediately in menu mode
		    if (m_psaiPlayMode == PsaiPlayMode.menuMode)
		    {

			    #if !(PSAI_NOLOG)
                    if (LogLevel.warnings <= Logger.Instance.LogLevel)
                    {
                    	Logger.Instance.Log("TriggerMusicTheme() ignored: Menu Mode is active", LogLevel.warnings);
                    }
			    #endif

			    return PsaiResult.commandIgnoredMenuModeActive;
		    }

		    else if (m_psaiPlayModeIntended == PsaiPlayMode.cutScene)
		    {
			    #if !(PSAI_NOLOG)
                    if (LogLevel.warnings <= Logger.Instance.LogLevel)
                    {
                    	Logger.Instance.Log("TriggerMusicTheme() ignored: Cutscene is active", LogLevel.warnings);
                    }
			    #endif

			    return PsaiResult.commandIgnoredCutsceneActive;
		    }

		    else if (m_psaiPlayMode == PsaiPlayMode.cutScene && m_psaiStateIntended == PsaiState.silence && m_currentSegmentPlaying != null)
		    {
			    #if !(PSAI_NOLOG)
			    {
                    if (LogLevel.info <= Logger.Instance.LogLevel)
                    {
                    	Logger.Instance.Log("special case: Cutscene Theme is still playing, continuing with theme " + argTheme.Name, LogLevel.info);
                    }
			    }
			    #endif

			    m_psaiState = PsaiState.playing;
			    m_psaiStateIntended = PsaiState.playing;

                return PlayThemeNowOrAtEndOfCurrentSegment(argTheme.id, argIntensity, argMusicDuration, true, false);						
		    }




		    //////////////////////////////////////////////////////////////////////////
		    // regular Mode
		    //////////////////////////////////////////////////////////////////////////


            // if we trigger a BasicMood shortly after ReturnToBasicMood(by End) has been called, we don't want to cancel the
            // return, but instead switch the Last Basic Mood to return to. In all other cases, cancel the Return process.
            if (m_returnToLastBasicMoodFlag)
            {
                if (argTheme.themeType != ThemeType.basicMood)
                {
                    m_returnToLastBasicMoodFlag = false;
                }                
            }


            if (argTheme.themeType == ThemeType.basicMood)
		    {
			    SetThemeAsLastBasicMood(argTheme);
		    }


            // always clear the Theme Queue, as the most recent trigger call is the one that counts.
            removeFirstFollowingThemeQueueEntry();

		
		    // nothing is playing -> play immediately
		    if (effectiveSegment == null || m_psaiState == PsaiState.silence || m_psaiState == PsaiState.rest)
		    {
                return PlayThemeNowOrAtEndOfCurrentSegment(argTheme.id, argIntensity, argMusicDuration, true, false);
		    }


            // special case: StopMusic(by End Segment) is in progress, and a Theme of lower or same priority is triggered
		    // -> conduct a seamless transition.
		    if (m_psaiStateIntended == PsaiState.silence && effectiveSegment != null)
		    {
                Theme effectiveTheme1 = m_soundtrack.getThemeById(effectiveSegment.ThemeId);
			    ThemeInterruptionBehavior tib = Theme.GetThemeInterruptionBehavior(effectiveTheme1.themeType, argTheme.themeType);

                if (tib == ThemeInterruptionBehavior.at_end_of_current_snippet || tib == ThemeInterruptionBehavior.never)
			    {
				    m_psaiStateIntended = PsaiState.playing;
				    return PlayThemeNowOrAtEndOfCurrentSegment(argTheme.id, argIntensity, argMusicDuration, false, false);
			    }			
		    }


		    // the effective Theme was triggered again? 
		    if (effectiveSegment.ThemeId == argTheme.id)
		    {
			    #if !(PSAI_NOLOG)
			    {
                    /*
                    if (LogLevel.debug <= Logger.Instance.LogLevel)
                    {
	                    StringBuilder sb = new StringBuilder();
	                    sb.Append("theme ");
	                    sb.Append(argTheme.Name);
	                    sb.Append(" is already playing and the SegmentEndApproaching timer is pending. Updating intensity to ");
	                    sb.Append(argIntensity);
	                    Logger.Instance.Log(sb.ToString(), LogLevel.debug);
                    }
                    */
			    }
			    #endif
                
                m_nonInterruptingTriggerOfHighestPriority.themeId = -1;		// clear any non-interrupting trigger call we may have received recently!  

                SetCurrentIntensityAndMusicDuration(argIntensity, argMusicDuration, true);
                m_psaiStateIntended = PsaiState.playing;
                return PsaiResult.OK;
		    }

            Theme effectiveTheme = m_soundtrack.getThemeById(effectiveSegment.ThemeId);
		    ThemeInterruptionBehavior themeInteruptionBehavior = Theme.GetThemeInterruptionBehavior(effectiveTheme.themeType, argTheme.themeType);

		    switch (themeInteruptionBehavior)
		    {
		    case ThemeInterruptionBehavior.immediately:
			    {
                    // don't push the interrupted Theme on the stack if GoToRest() or StopMusic() has just been called.
                    if (argTheme.themeType == ThemeType.shock && m_psaiStateIntended == PsaiState.playing) 
                    {
                        PushEffectiveThemeToThemeQueue(PsaiPlayMode.regular);
                    }
                    else
                    {
                        m_nonInterruptingTriggerOfHighestPriority.themeId = -1;
                    }

                    return PlayThemeNowOrAtEndOfCurrentSegment(argTheme.id, argIntensity, argMusicDuration, true, false);                
			    }
			    //break;

		    case ThemeInterruptionBehavior.at_end_of_current_snippet:
			    {
				    return HandleNonInterruptingTriggerCall(argTheme, argIntensity, argMusicDuration);				
			    }
			    //break;

		    case ThemeInterruptionBehavior.never:
			    {
                    if (argTheme.themeType != ThemeType.basicMood)
				    {
					    pushThemeToThemeQueue(argTheme.id, argIntensity, argMusicDuration, false, 0, PsaiPlayMode.regular, false);

					    #if !(PSAI_NOLOG)
					    {
                            if (LogLevel.info <= Logger.Instance.LogLevel)
                            {
	                            StringBuilder sb = new StringBuilder();
	                            sb.Append("Theme ");
	                            sb.Append(argTheme.Name);
	                            sb.Append(" has been queued for direct playback after the intensity of the current Theme has dropped to zero.");
							    Logger.Instance.Log(sb.ToString(), LogLevel.info);
                            }
					    }
					    #endif
				    }
				    return PsaiResult.OK;
			    }
			    //break;
		    }

		

		    #if !(PSAI_NOLOG)
		    {
                if (LogLevel.errors <= Logger.Instance.LogLevel)
                {
	                StringBuilder sb = new StringBuilder();
	                sb.Append("INTERNAL ERROR: end of TriggerMusicTheme() reached without returning a proper returnCode. ");
	                sb.Append("argThemeId=");
	                sb.Append(argTheme.id);
	                sb.Append(" m_currentTheme=");
	                sb.Append(m_effectiveTheme);
	                if (m_effectiveTheme != null)
	                {
	                    sb.Append(" m_currentTheme id=");
	                    sb.Append(m_effectiveTheme.id);
	                    sb.Append("  m_currentTheme themeType=");
	                    sb.Append(m_effectiveTheme.themeType);
	                }
	                Logger.Instance.Log(sb.ToString(), LogLevel.errors);
                }
		    }
		    #endif

		    return PsaiResult.internal_error;
        }
예제 #15
0
        /**
         * @param listOfSnippetsWithValidTransitionSequencesToTargetTheme - a list of Snippets that have a valid Transition-Sequence to or directly compatible followers in a given TargetTheme.
         */
        private void SetTheNextSegmentToShortestTransitionSequenceToTargetThemeForAllSourceSegmentsOfTheSegmentsInThisList(Segment[] listOfSnippetsWithValidTransitionSequencesToTargetTheme, Soundtrack soundtrack, Theme targetTheme)
        {
            /*
            #if !(PSAI_NOLOG)
                if (LogLevel.debug <= Logger.Instance.LogLevel)
                {
                    Logger.Instance.Log("SetTheNextSegmentToShortestTransitionSequenceToTargetThemeForAllSourceSegmentsOfTheSegmentsInThisList() called, listOfSnippets.Length=" + listOfSnippetsWithValidEndSequences.Length, LogLevel.debug);
                    StringBuilder sb = new StringBuilder();
                    foreach (Snippet argSnippet in listOfSnippetsWithValidEndSequences)
                    {
                        sb.Append(argSnippet.name);
                        sb.Append(" intensity=");
                        sb.Append(argSnippet.intensity);
                        sb.Append(" nextSnippetToShEndSeq=");
                        sb.Append(argSnippet.nextSnippetToShortestEndSequence);
                        sb.Append("    ");
                    }
                    Logger.Instance.Log(sb.ToString(), LogLevel.debug);
                }
            #endif
            */

            Dictionary<Segment, List<Segment>> mapWaypointAlternativesForSnippet = new Dictionary<Segment, List<Segment>>();
            foreach (Segment transitionSnippet in listOfSnippetsWithValidTransitionSequencesToTargetTheme)
            {
                List<Segment> sourceSnippets = GetSetOfAllSourceSegmentsCompatibleToSegment(transitionSnippet, Logik.COMPATIBILITY_PERCENTAGE_SAME_GROUP, SegmentSuitability.none);
                sourceSnippets.Remove(transitionSnippet);

                foreach (Segment sourceSnippet in sourceSnippets)
                {
                    if (sourceSnippet.MapOfNextTransitionSegmentToTheme.ContainsKey(targetTheme.id) == false
                        && sourceSnippet.CheckIfAtLeastOneDirectTransitionOrLayeringIsPossible(soundtrack, targetTheme.id) == false
                        && sourceSnippet.ThemeId == transitionSnippet.ThemeId)
                    {
                        if (mapWaypointAlternativesForSnippet.ContainsKey(sourceSnippet) == false)
                        {
                            mapWaypointAlternativesForSnippet[sourceSnippet] = new List<Segment>();
                        }
                        mapWaypointAlternativesForSnippet[sourceSnippet].Add(transitionSnippet);
                    }
                }
            }

            foreach (Segment snippet in mapWaypointAlternativesForSnippet.Keys)
            {
                snippet.MapOfNextTransitionSegmentToTheme[targetTheme.id] = snippet.ReturnSegmentWithLowestIntensityDifference(mapWaypointAlternativesForSnippet[snippet]);
            }

            Segment[] snippetsAdded = new Segment[mapWaypointAlternativesForSnippet.Count];
            mapWaypointAlternativesForSnippet.Keys.CopyTo(snippetsAdded, 0);

            if (snippetsAdded.Length > 0)
            {
                SetTheNextSegmentToShortestTransitionSequenceToTargetThemeForAllSourceSegmentsOfTheSegmentsInThisList(snippetsAdded, soundtrack, targetTheme);
            }
        }
예제 #16
0
        /* This method is responsible to link each Segment of a Theme to the Target Theme
        *  in the shortest path possible. If multiple compatible Segments exist, the one with the
        *  best-matching intensity will be chosen.
        *  After the algorithm has finished, each Snippet's _mapCompatibleSegmentsToTheme will hold
        *  the Segment to be played next when a Theme Transition is in progress, or NULL
        *  if either no transition is possible at all, or if a direct transition is possible.
        */
        internal void BuildSequencesToTargetThemeForAllSegments(Soundtrack soundtrack, Theme targetTheme)
        {
            foreach (Segment snippet in m_segments)
            {
                snippet.MapOfNextTransitionSegmentToTheme.Remove(targetTheme.id);
            }

            List<Segment> snippetsAddedInLastTier = new List<Segment>();
            foreach (Segment snippet in m_segments)
            {
                if (snippet.CheckIfAtLeastOneDirectTransitionOrLayeringIsPossible(soundtrack, targetTheme.id) == true)
                {
                    snippetsAddedInLastTier.Add(snippet);
                }
            }

            SetTheNextSegmentToShortestTransitionSequenceToTargetThemeForAllSourceSegmentsOfTheSegmentsInThisList(snippetsAddedInLastTier.ToArray(), soundtrack, targetTheme);

            #if !(PSAI_NOLOG)
            {
                if (LogLevel.debug <= Logger.Instance.LogLevel)
                {
                    StringBuilder sb = new StringBuilder();
                    sb.Append("BuildSequencesToTargetThemeForAllSegments completed for Theme ");
                    sb.Append(this);
                    sb.Append(" to Theme ");
                    sb.Append(targetTheme);
                    sb.Append("\n");
                    foreach (Segment snippet in m_segments)
                    {
                        sb.Append(snippet);
                        sb.Append(" -> ");

                        if (snippet.MapOfNextTransitionSegmentToTheme.ContainsKey(targetTheme.id) == false)
                        {
                            sb.Append(" DirectTransition:");
                            sb.Append(snippet.CheckIfAtLeastOneDirectTransitionOrLayeringIsPossible(soundtrack, targetTheme.id));
                        }
                        else
                        {
                            sb.Append(snippet.MapOfNextTransitionSegmentToTheme[targetTheme.id].ToString());
                        }
                        sb.Append("\n");
                    }
                    Logger.Instance.Log(sb.ToString(), LogLevel.debug);
                }
            }
            #endif
        }