public bool BeginPlaySong(Song s, bool pal, int startNote, IRegisterListener listener = null) { song = s; famitrackerTempo = song.UsesFamiTrackerTempo; famitrackerSpeed = song.FamitrackerSpeed; famitrackerNativeTempo = pal ? Song.NativeTempoPAL : Song.NativeTempoNTSC; palPlayback = pal; playPosition = startNote; playPattern = 0; playNote = 0; tempoCounter = 0; ResetFamiStudioTempo(true); channelStates = CreateChannelStates(song.Project, apuIndex, song.Project.ExpansionNumChannels, palPlayback, listener); NesApu.InitAndReset(apuIndex, sampleRate, palPlayback, GetNesApuExpansionAudio(song.Project), song.Project.ExpansionNumChannels, dmcCallback); UpdateChannelsMuting(); //Debug.WriteLine($"START SEEKING!!"); if (startNote != 0) { NesApu.StartSeeking(apuIndex); while (song.GetPatternStartNote(playPattern) + playNote < startNote) { //Debug.WriteLine($"Seek Frame {song.GetPatternStartNote(playPattern) + playNote}!"); int numFramesToRun = UpdateTempoEnvelope(); for (int i = 0; i < numFramesToRun; i++) { //Debug.WriteLine($" Seeking Frame {song.GetPatternStartNote(playPattern) + playNote}!"); AdvanceChannels(); UpdateChannelsEnvelopesAndAPU(); if (!AdvanceSong(song.Length, LoopMode.None)) { return(false); } } } NesApu.StopSeeking(apuIndex); } AdvanceChannels(); UpdateChannelsEnvelopesAndAPU(); EndFrame(); playPosition = song.GetPatternStartNote(playPattern) + playNote; return(true); }
public bool BeginPlaySong(Song s, bool pal, int startNote) { song = s; famitrackerTempo = song.UsesFamiTrackerTempo; famitrackerSpeed = song.FamitrackerSpeed; palPlayback = pal; playPosition = startNote; playLocation = new NoteLocation(0, 0); frameNumber = 0; famitrackerTempoCounter = 0; channelStates = CreateChannelStates(this, song.Project, apuIndex, song.Project.ExpansionNumN163Channels, palPlayback); NesApu.InitAndReset(apuIndex, sampleRate, palPlayback, tndMode, song.Project.ExpansionAudioMask, song.Project.ExpansionNumN163Channels, dmcCallback); ResetFamiStudioTempo(); UpdateChannelsMuting(); //Debug.WriteLine($"START SEEKING!!"); if (startNote != 0) { seeking = true; NesApu.StartSeeking(apuIndex); AdvanceChannels(); UpdateChannels(); UpdateTempo(); while (playLocation.ToAbsoluteNoteIndex(song) < startNote - 1) { if (!PlaySongFrameInternal(true)) { break; } } NesApu.StopSeeking(apuIndex); seeking = false; } else { AdvanceChannels(); UpdateChannels(); UpdateTempo(); } playPosition = playLocation.ToAbsoluteNoteIndex(song); UpdateBeat(); EndFrame(); return(true); }
public bool BeginPlaySong(Song s, bool pal, int startNote) { song = s; famitrackerTempo = song.UsesFamiTrackerTempo; famitrackerSpeed = song.FamitrackerSpeed; famitrackerNativeTempo = pal ? Song.NativeTempoPAL : Song.NativeTempoNTSC; palMode = pal; playPosition = startNote; playPattern = 0; playNote = 0; tempoCounter = 0; firstFrame = true; ResetFamiStudioTempo(true); channelStates = CreateChannelStates(song.Project, apuIndex, song.Project.ExpansionNumChannels, palMode); NesApu.InitAndReset(apuIndex, SampleRate, palMode, GetNesApuExpansionAudio(song.Project), song.Project.ExpansionNumChannels, dmcCallback); if (startNote != 0) { NesApu.StartSeeking(apuIndex); #if DEBUG NesApu.seeking = true; #endif while (song.GetPatternStartNote(playPattern) + playNote < startNote) { foreach (var channel in channelStates) { channel.Advance(song, playPattern, playNote, famitrackerSpeed, famitrackerNativeTempo); channel.ProcessEffects(song, playPattern, playNote, ref famitrackerSpeed); channel.UpdateEnvelopes(); channel.UpdateAPU(); } if (!AdvanceSong(song.Length, LoopMode.None)) { return(false); } //Debug.WriteLine($"Seeking Frame {song.GetPatternStartNote(playPattern) + playNote}!"); UpdateFrameSkip(); } NesApu.StopSeeking(apuIndex); #if DEBUG NesApu.seeking = false; #endif } return(true); }
public bool BeginPlaySong(Song s, bool pal, int startNote) { song = s; famitrackerTempo = song.UsesFamiTrackerTempo; famitrackerSpeed = song.FamitrackerSpeed; palPlayback = pal; playPosition = startNote; playPattern = 0; playNote = 0; frameNumber = 0; famitrackerTempoCounter = 0; channelStates = CreateChannelStates(this, song.Project, apuIndex, song.Project.ExpansionNumChannels, palPlayback); NesApu.InitAndReset(apuIndex, sampleRate, palPlayback, GetNesApuExpansionAudio(song.Project.ExpansionAudio), song.Project.ExpansionNumChannels, dmcCallback); ResetFamiStudioTempo(true); UpdateChannelsMuting(); //Debug.WriteLine($"START SEEKING!!"); if (startNote != 0) { NesApu.StartSeeking(apuIndex); AdvanceChannels(); UpdateChannels(); UpdateFamitrackerTempo(famitrackerSpeed, song.FamitrackerTempo); while (song.GetPatternStartNote(playPattern) + playNote < startNote) { if (!PlaySongFrameInternal(true)) { break; } } NesApu.StopSeeking(apuIndex); } else { AdvanceChannels(); UpdateChannels(); UpdateFamitrackerTempo(famitrackerSpeed, song.FamitrackerTempo); } EndFrame(); playPosition = song.GetPatternStartNote(playPattern) + playNote; return(true); }
unsafe void PlayerThread(object o) { var startInfo = (SongPlayerStartInfo)o; var song = startInfo.song; var channels = PlayerBase.CreateChannelStates(song.Project, apuIndex); var advance = true; var tempoCounter = 0; var playPattern = 0; var playNote = 0; var jumpPattern = -1; var jumpNote = -1; var speed = song.Speed; playPosition = startInfo.frame; NesApu.InitAndReset(apuIndex, SampleRate, GetNesApuExpansionAudio(song.Project), dmcCallback); if (startInfo.frame != 0) { NesApu.StartSeeking(apuIndex); #if DEBUG NesApu.seeking = true; #endif while (playPattern * song.PatternLength + playNote < startInfo.frame) { var dummyAdvance = false; if (!AdvanceTempo(song, speed, LoopMode.None, ref tempoCounter, ref playPattern, ref playNote, ref jumpPattern, ref jumpNote, ref dummyAdvance)) { break; } foreach (var channel in channels) { channel.Advance(song, playPattern, playNote); channel.ProcessEffects(song, playPattern, playNote, ref jumpPattern, ref jumpNote, ref speed); channel.UpdateEnvelopes(); channel.UpdateAPU(); } } NesApu.StopSeeking(apuIndex); #if DEBUG NesApu.seeking = false; #endif jumpPattern = -1; jumpNote = -1; } var waitEvents = new WaitHandle[] { stopEvent, frameEvent }; while (true) { int idx = WaitHandle.WaitAny(waitEvents); if (idx == 0) { break; } // !advance is to handle first frame. if (!advance && !AdvanceTempo(song, speed, loopMode, ref tempoCounter, ref playPattern, ref playNote, ref jumpPattern, ref jumpNote, ref advance)) { break; } // Advance to next note. if (advance) { playPosition = playPattern * song.PatternLength + playNote; foreach (var channel in channels) { channel.Advance(song, playPattern, playNote); channel.ProcessEffects(song, playPattern, playNote, ref jumpPattern, ref jumpNote, ref speed); } advance = false; } // Update envelopes + APU registers. foreach (var channel in channels) { channel.UpdateEnvelopes(); channel.UpdateAPU(); } // Mute. for (int i = 0; i < channels.Length; i++) { NesApu.EnableChannel(apuIndex, i, (channelMask & (1 << i))); } EndFrameAndQueueSamples(); } audioStream.Stop(); while (sampleQueue.TryDequeue(out _)) { ; } }