/** * create the item that is able to play the level's music based on the music script. * If a mainSoundTrack=null is passed, no time syncing to a main sound track is used. */ public LevelMusic( SoundTrackEvent musicScript, SampleSoundEvent mainSoundTrack) : base() { musicRp = new RenderParams(); musicRp.RenderAheadTime = 15.0; this.musicScript = musicScript; this.mainSoundTrack = mainSoundTrack; }
/** clone settings of another into this object! This is a way to avoid excessive new object creation. Supports object re-use */ public void SetTo(RenderParams other) { this.Time = other.Time; this.AbsTime = other.AbsTime; this.Ampl = other.Ampl; this.Pan = other.Pan; this.HierarchyID = other.HierarchyID; this.RenderAheadTime = other.RenderAheadTime; }
/** * render audio in the script 'ev', with parameters 'rp'. Multiple rendered scripts may run * in parrallel. * Call for example once per frame per script, but no firm requirements posed for this. * See also: Update() */ public RenderCanvas Render(SoundEvent ev, RenderParams rp) { rp.AbsTime = rp.Time; RenderCanvas canvas = new RenderCanvas(); // TODO option to recycle objects here, avoid creation? ev.Render(rp, canvas); return(canvas); }
public override bool Render(RenderParams rp, RenderCanvas c) { if (!Active) return false; if (rp.Time >= 0 && !renderDone ) // yes its my turn! { // spawn new item ... parentForItem.Add(gameItem); renderDone = true; } else if (rp.Time < 0) { // if time < 0 reset back the render flag eg for purpose of replay of this script. renderDone = false; } return true; }
public override bool Render(RenderParams parentRp, RenderCanvas canvas) { if (!Active) return false; _rp = new RenderParams(parentRp); AdaptRenderParams(_rp); //Util.Log("Render HID=" + rp.HierarchyID + " ID=" + this.ID + "\n"); // make a new canvas - anything painted on here by children, will // be used in this SOundEvent. RenderCanvas myCanvas = new RenderCanvas(); // Render to rp/myCanvas, to retrieve adapted render-params based on possible // effects attached to me as child nodes. RenderChildren(_rp, myCanvas); // render my audio ... if within the right time if (_rp.Time >= 0 && _rp.Time < Duration ) { _audio.Render(_rp, myCanvas,_dspList, _audioRepeats); canvas.TimeMarker = myCanvas.TimeMarker; return true; } return false; }
FMOD.Channel PlaySample(RenderParams rp, RenderCanvas canvas, List<FMOD.DSP> dspList ) { FMOD.Channel channel = null; FMOD.RESULT r = MusicEngine.AudioEngine.playSound(FMOD.CHANNELINDEX.FREE, _sound, true, ref channel); if (r == FMOD.RESULT.OK && channel != null) { // set regular play properties AdaptChannelSettings(channel, rp, canvas); // set play position uint tMs = (uint)Math.Round(rp.Time * 1000.0); if (tMs > 0) { // only set position if there is a need r = channel.setPosition(tMs, FMOD.TIMEUNIT.MS); #if DEBUG Util.Log(" setPos(" + tMs + ")"); #endif } // set optional DSP unit(s) on channel if (r == FMOD.RESULT.OK) { FMOD.DSPConnection conn = null; foreach (FMOD.DSP d in dspList) { r = channel.addDSP(d, ref conn); // TODO errcheck } // go - start playing if (r == FMOD.RESULT.OK) { r = channel.setPaused(false); } } } // if Util.ERRCHECK(r); return channel; }
/** * called when this sample/effect should render itself, possibly spawning a new * playing instance or modifying an already playing instance. */ internal void Render(RenderParams rp, RenderCanvas canvas, List<FMOD.DSP> dspList , int audioRepeats) { #if DEBUG Util.Log("Render HID=" + rp.HierarchyID + " T=" + Math.Round(rp.Time,3) + " AbsT=" + Math.Round(rp.AbsTime,3) + " A="+ Math.Round(rp.Ampl,3) + "\n"); #endif // check if duration is not exceeded if (rp.Time > _soundDuration * ((double)audioRepeats) ) return; bool wasPlaying = _nowPlayingList.ContainsKey(rp.HierarchyID); FMOD.Channel channel = null; FMOD.RESULT r; if (wasPlaying) { channel = _nowPlayingList[rp.HierarchyID]; // check if still playing now bool isPlayingNow = false; r = channel.isPlaying(ref isPlayingNow); //Util.ERRCHECK(r); // TODO is this needed? if(isPlayingNow) { // if so, adapt sample properties only. AdaptChannelSettings(channel, rp, canvas); // check playing time uint playPosMs = 0; int idealPlayPosMs = (int) Math.Round(rp.Time * 1000.0); channel.getPosition(ref playPosMs, FMOD.TIMEUNIT.MS); if (Math.Abs(((int)playPosMs) - idealPlayPosMs) > 5000 && idealPlayPosMs >= 0) // FIXME specify error margin better, somewhere? configurable per sample? { //FIXME HACK enable tracking when needed !!! below. channel.setPosition((uint)idealPlayPosMs, FMOD.TIMEUNIT.MS); playPosMs = (uint)idealPlayPosMs; } // store current pos on canvas if (canvas.TimeMarker == 0) { canvas.TimeMarker = ((double)playPosMs) / 1000.0; } } else { // if not anymore, remove from list _nowPlayingList.Remove(rp.HierarchyID); } } else { // was not playing but should be rendered - hence, initiate playing now if (rp.Time < _soundDuration - 0.050 ) // extra safety margin - do not start if close to end. TODO configurable time? { channel = PlaySample(rp, canvas, dspList); channel.setLoopCount(audioRepeats - 1); if (channel != null) { #if DEBUG Util.Log("Play HID=" + rp.HierarchyID + " T=" + Math.Round(rp.Time, 3) + " AbsT=" + Math.Round(rp.AbsTime, 3) + " A=" + Math.Round(rp.Ampl, 3) + "\n"); #endif // store playing sound in the table _nowPlayingList[rp.HierarchyID] = channel; } else { Util.Log("Play FAILED rp.H-ID=" + rp.HierarchyID + " rp.Time=" + rp.Time + " rp.AbsTime=" + rp.AbsTime + "\n"); } } } }
/** * adapt a running sample according to renderparams and canvas result */ internal void AdaptChannelSettings(FMOD.Channel channel, RenderParams rp, RenderCanvas canvas) { double a = rp.Ampl * canvas.AmplMultiply + canvas.AmplAdd; double p = rp.Pan + canvas.Pan; channel.setVolume((float)a); channel.setPan((float)p); }
public RenderParams(RenderParams other) { this.SetTo(other); }
/** * render audio in the script 'ev', with parameters 'rp'. Multiple rendered scripts may run * in parrallel. * Call for example once per frame per script, but no firm requirements posed for this. * See also: Update() */ public RenderCanvas Render(SoundEvent ev, RenderParams rp) { rp.AbsTime = rp.Time; RenderCanvas canvas = new RenderCanvas(); // TODO option to recycle objects here, avoid creation? ev.Render(rp,canvas); return canvas; }