private static int LoadAndMergePatternList(ProjectLoadBuffer serializer, Song song)
        {
            // Remap whatever original song we had to the current one.
            int songId = -1;

            serializer.Serialize(ref songId);
            serializer.RemapId(songId, song.Id);

            int numPatterns = 0;

            serializer.Serialize(ref numPatterns);

            var patternIdNameMap = new List <Tuple <int, int, string> >();

            for (int i = 0; i < numPatterns; i++)
            {
                var patId      = 0;
                var patChannel = 0;
                var patName    = "";
                serializer.Serialize(ref patId);
                serializer.Serialize(ref patChannel);
                serializer.Serialize(ref patName);
                patternIdNameMap.Add(new Tuple <int, int, string>(patId, patChannel, patName));
            }

            var dummyPattern = new Pattern();

            // Match patterns by name, create missing ones and remap IDs.
            for (int i = 0; i < numPatterns; i++)
            {
                var patId      = patternIdNameMap[i].Item1;
                var patChannel = patternIdNameMap[i].Item2;
                var patName    = patternIdNameMap[i].Item3;

                if (serializer.Project.IsChannelActive(patChannel))
                {
                    var existingPattern = song.GetChannelByType(patChannel).GetPattern(patName);

                    if (existingPattern != null)
                    {
                        serializer.RemapId(patId, existingPattern.Id);
                        dummyPattern.SerializeState(serializer); // Skip
                    }
                    else
                    {
                        var pattern = song.GetChannelByType(patChannel).CreatePattern(patName);
                        serializer.RemapId(patId, pattern.Id);
                        pattern.SerializeState(serializer);
                    }
                }
                else
                {
                    serializer.RemapId(patId, -1);
                    dummyPattern.SerializeState(serializer); // Skip
                }
            }

            return(numPatterns);
        }
Exemple #2
0
        public void Advance(Song song, int patternIdx, int noteIdx)
        {
            var channel = song.GetChannelByType(channelType);
            var pattern = channel.PatternInstances[patternIdx];

            if (pattern == null)
            {
                return;
            }

            var newNote = pattern.Notes[noteIdx];

            if (newNote.IsValid)
            {
                slideStep = 0;

                if (newNote.IsSlideNote)
                {
                    var noteTable = NesApu.GetNoteTableForChannelType(channel.Type, false);

                    if (channel.ComputeSlideNoteParams(patternIdx, noteIdx, noteTable, out slidePitch, out slideStep, out _))
                    {
                        newNote.Value = (byte)newNote.SlideNoteTarget;
                    }
                }

                PlayNote(newNote);
            }
            else if (newNote.HasVolume)
            {
                note.Volume = newNote.Volume;
            }
        }
Exemple #3
0
        public void ProcessEffects(Song song, int patternIdx, int noteIdx, ref int speed, bool allowJump = true)
        {
            var pattern = song.GetChannelByType(channelType).PatternInstances[patternIdx];

            if (pattern == null)
            {
                return;
            }

            if (pattern.Notes.TryGetValue(noteIdx, out var tmpNote))
            {
                if (tmpNote.HasSpeed)
                {
                    speed = tmpNote.Speed;
                }

                if (tmpNote.HasVibrato)
                {
                    if (tmpNote.VibratoDepth != 0 && tmpNote.VibratoDepth != 0)
                    {
                        envelopes[Envelope.Pitch]      = Envelope.CreateVibratoEnvelope(tmpNote.VibratoSpeed, tmpNote.VibratoDepth);
                        envelopeIdx[Envelope.Pitch]    = 0;
                        envelopeValues[Envelope.Pitch] = 0;
                        pitchEnvelopeOverride          = true;
                    }
                    else
                    {
                        envelopes[Envelope.Pitch] = null;
                        pitchEnvelopeOverride     = false;
                    }
                }
            }
        }
Exemple #4
0
 public void Validate(Song song, Dictionary <int, object> idMap)
 {
     Debug.Assert(this == song.GetChannelByType(type));
     Debug.Assert(this.song == song);
     foreach (var inst in patternInstances)
     {
         Debug.Assert(inst == null || patterns.Contains(inst));
     }
     foreach (var pat in patterns)
     {
         pat.Validate(this, idMap);
     }
 }
Exemple #5
0
        public void Advance(Song song, int patternIdx, int noteIdx, ref int famitrackerSpeed)
        {
            // When advancing row, if there was a delayed note, play it immediately. That's how FamiTracker does it.
            if (delayedNote != null)
            {
                PlayNote(delayedNote, delayedNoteSlidePitch, delayedNoteSlideStep);
                delayedNote        = null;
                delayedNoteCounter = 0;
            }

            var channel = song.GetChannelByType(channelType);
            var pattern = channel.PatternInstances[patternIdx];

            if (pattern == null)
            {
                return;
            }

            if (pattern.Notes.TryGetValue(noteIdx, out var newNote))
            {
                // We dont delay speed effects. This is not what FamiTracker does, but I dont care.
                // There is a special place in hell for people who delay speed effect.
                if (newNote.HasSpeed)
                {
                    famitrackerSpeed = newNote.Speed;
                }

                // Slide params needs to be computed right away since we wont have access to the play position/channel later.
                int noteSlidePitch = 0;
                int noteSlideStep  = 0;

                if (newNote.IsValid && newNote.IsSlideNote)
                {
                    channel.ComputeSlideNoteParams(newNote, patternIdx, noteIdx, famitrackerSpeed, noteTable, palPlayback, true, out noteSlidePitch, out noteSlideStep, out _);
                }

                // Store note for later if delayed.
                if (newNote.HasNoteDelay)
                {
                    delayedNote           = newNote;
                    delayedNoteCounter    = newNote.NoteDelay + 1;
                    delayedNoteSlidePitch = noteSlidePitch;
                    delayedNoteSlideStep  = noteSlideStep;
                    return;
                }

                PlayNote(newNote, noteSlidePitch, noteSlideStep);
            }
        }
Exemple #6
0
        public void Advance(Song song, NoteLocation location, ref int famitrackerSpeed)
        {
            // When advancing row, if there was a delayed note, play it immediately. That's how FamiTracker does it.
            if (delayedNote != null)
            {
                PlayNote(delayedNote, delayedNoteSlidePitch, delayedNoteSlideStep);
                delayedNote        = null;
                delayedNoteCounter = 0;
            }

            var channel = song.GetChannelByType(channelType);
            var pattern = channel.PatternInstances[location.PatternIndex];

            if (pattern == null)
            {
                return;
            }

            pattern.Notes.TryGetValue(location.NoteIndex, out var newNote);

            var needClone = true;

            // Generate a release note if the release counter reaches zero.
            if (releaseCounter > 0 && --releaseCounter == 0 && (newNote == null || !newNote.IsMusicalOrStop))
            {
                newNote       = newNote == null ? new Note() : newNote.Clone();
                newNote.Value = Note.NoteRelease;
                needClone     = false;
            }

            // Generate a stop note if the stop counter reaches zero.
            if (durationCounter > 0 && --durationCounter == 0 && (newNote == null || !newNote.IsMusicalOrStop))
            {
                newNote       = newNote == null ? new Note() : newNote.Clone();
                newNote.Value = Note.NoteStop;
                needClone     = false;
            }

            if (newNote != null)
            {
                // We dont delay speed effects. This is not what FamiTracker does, but I dont care.
                // There is a special place in hell for people who delay speed effect.
                if (newNote.HasSpeed)
                {
                    famitrackerSpeed = newNote.Speed;
                }

                // Slide params needs to be computed right away since we wont have access to the play position/channel later.
                int noteSlidePitch = 0;
                int noteSlideStep  = 0;

                if (newNote.IsMusical)
                {
                    if (newNote.IsSlideNote)
                    {
                        channel.ComputeSlideNoteParams(newNote, location, famitrackerSpeed, noteTable, palPlayback, true, out noteSlidePitch, out noteSlideStep, out _);
                    }

                    if (newNote.HasRelease)
                    {
                        releaseCounter = newNote.Release;
                    }

                    durationCounter = newNote.Duration;
                }

                // Store note for later if delayed.
                if (newNote.HasNoteDelay)
                {
                    delayedNote           = newNote;
                    delayedNoteCounter    = newNote.NoteDelay + 1;
                    delayedNoteSlidePitch = noteSlidePitch;
                    delayedNoteSlideStep  = noteSlideStep;
                    return;
                }

                PlayNote(newNote, noteSlidePitch, noteSlideStep, needClone);
            }
        }
Exemple #7
0
        public void Advance(Song song, int patternIdx, int noteIdx, int famitrackerSpeed, int famitrackerBaseTempo)
        {
            var channel = song.GetChannelByType(channelType);
            var pattern = channel.PatternInstances[patternIdx];

            if (pattern == null)
            {
                return;
            }

            if (pattern.Notes.TryGetValue(noteIdx, out var newNote))
            {
                newNote = newNote.Clone();

                if (newNote.IsValid)
                {
                    if (!newNote.IsRelease)
                    {
                        slideStep = 0;
                    }

                    if (newNote.IsSlideNote)
                    {
                        if (channel.ComputeSlideNoteParams(newNote, patternIdx, noteIdx, famitrackerSpeed, famitrackerBaseTempo, noteTable, out slidePitch, out slideStep, out _))
                        {
                            newNote.Value = (byte)newNote.SlideNoteTarget;
                        }
                    }

                    if (!newNote.HasVolume && note.HasVolume)
                    {
                        newNote.Volume = note.Volume;
                    }
                    if (!newNote.HasFinePitch && note.HasFinePitch)
                    {
                        newNote.FinePitch = note.FinePitch;
                    }
                    if (!newNote.HasFdsModDepth && note.HasFdsModDepth)
                    {
                        newNote.FdsModDepth = note.FdsModDepth;
                    }
                    if (!newNote.HasFdsModSpeed && note.HasFdsModSpeed)
                    {
                        newNote.FdsModSpeed = note.FdsModSpeed;
                    }
                    if (newNote.Instrument == null && note.Instrument != null)
                    {
                        newNote.Instrument = note.Instrument;
                    }

                    PlayNote(newNote);
                }
                else
                {
                    if (newNote.HasVolume)
                    {
                        note.Volume = newNote.Volume;
                    }
                    if (newNote.HasFinePitch)
                    {
                        note.FinePitch = newNote.FinePitch;
                    }
                    if (newNote.HasFdsModDepth)
                    {
                        note.FdsModDepth = newNote.FdsModDepth;
                    }
                    if (newNote.HasFdsModSpeed)
                    {
                        note.FdsModSpeed = newNote.FdsModSpeed;
                    }
                    if (newNote.Instrument != null)
                    {
                        note.Instrument = newNote.Instrument;
                    }
                }
            }
        }