Пример #1
0
        static void SplitImplicitSlides(List <Bar> bars)
        {
            // Unfortunately, for targeted slides, Rocksmith does not usually follow the sliding note
            // with a target note, so the target note may be implied only. Of course, this does not
            // work for our export, so if we find such a case, we need to split the sliding note into
            // two and set the second one to the target.
            Chord lastChord = null;

            for (int b = 0; b < bars.Count; ++b)
            {
                var bar     = bars[b];
                var nextBar = (b < bars.Count - 1) ? bars[b + 1] : null;
                for (int i = 0; i < bar.Chords.Count; ++i)
                {
                    var chord     = bar.Chords[i];
                    var nextChord = (i < bar.Chords.Count - 1) ? bar.Chords[i + 1] : ((nextBar != null) ? nextBar.Chords.FirstOrDefault() : null);
                    // see if there's an unmatched slide in the current chord.
                    foreach (var kvp in chord.Notes)
                    {
                        var note = kvp.Value;
                        if (note.Slide == Note.SlideType.ToNext)
                        {
                            if (!note.LinkNext || nextChord == null || !nextChord.Notes.ContainsKey(kvp.Key) ||
                                nextChord.Notes[kvp.Key].Fret != note.SlideTarget)
                            {
                                // found an instance where we need to set the slide up manually
                                if (note._Extended && lastChord != null && lastChord.Notes.ContainsKey(kvp.Key))
                                {
                                    // this note was already split previously, so move the
                                    // slide one step back and change this to the target
                                    var prevNote = lastChord.Notes[kvp.Key];
                                    prevNote.Slide       = note.Slide;
                                    prevNote.SlideTarget = note.SlideTarget;
                                    note.Fret            = note.SlideTarget;
                                    note.Slide           = Note.SlideType.None;
                                    note.SlideTarget     = -1;
                                }
                                else
                                {
                                    // split the chord, ideally in half, but take care to use durations
                                    // that are valid
                                    int duration  = chord.Duration / 2 + 1;
                                    int remaining = chord.Duration - duration;
                                    while (duration >= 2)
                                    {
                                        if (RhythmDetector.PrintableDurations.Contains(duration) &&
                                            RhythmDetector.PrintableDurations.Contains(remaining))
                                        {
                                            break;
                                        }
                                        --duration;
                                        ++remaining;
                                    }
                                    if (!RhythmDetector.PrintableDurations.Contains(duration) ||
                                        !RhythmDetector.PrintableDurations.Contains(remaining))
                                    {
                                        Console.WriteLine("  WARNING: Cannot split slide! Leaving incomplete as is...");
                                        continue;
                                    }
                                    var newChord = SplitChord(chord, bar.GetDurationLength(chord.Start, duration));
                                    foreach (var kvp2 in newChord.Notes)
                                    {
                                        if (kvp2.Value.Slide == Note.SlideType.ToNext)
                                        {
                                            kvp2.Value.Fret = kvp2.Value.SlideTarget;
                                            var prevNote = chord.Notes[kvp2.Key];
                                            prevNote.Slide         = Note.SlideType.ToNext;
                                            prevNote.SlideTarget   = kvp2.Value.Fret;
                                            kvp2.Value.Slide       = Note.SlideType.None;
                                            kvp2.Value.SlideTarget = -1;
                                        }
                                    }
                                    newChord.Duration = remaining;
                                    chord.Duration    = duration;
                                    bar.Chords.Insert(i + 1, newChord);
                                    nextChord = newChord;
                                }
                            }
                        }
                    }
                    lastChord = chord;
                }
            }
        }
Пример #2
0
        private void WriteBeat(Chord chord, int trackNumber, int numStrings, bool changeTempo, int newTempo)
        {
            const Byte  DOTTED_NOTE    = 1;
            const Byte  CHORD_DIAGRAM  = (1 << 1);
            const Byte  TEXT           = (1 << 2);
            const Byte  BEAT_EFFECTS   = (1 << 3);
            const Byte  MIX_TABLE      = (1 << 4);
            const Byte  TUPLET         = (1 << 5);
            const Byte  REST           = (1 << 6);
            const short STRING_EFFECTS = (1 << 5);
            const Byte  TAPPING        = 1;
            const Byte  SLAPPING       = 2;
            const Byte  POPPING        = 3;

            // figure out beat duration
            bool  dotted   = false;
            bool  triplet  = false;
            SByte duration = 0;

            switch (chord.Duration)
            {
            case 192:
                duration = -2;
                break;

            case 144:
                duration = -1;
                dotted   = true;
                break;

            case 96:
                duration = -1;
                break;

            case 72:
                duration = 0;
                dotted   = true;
                break;

            case 48:
                duration = 0;
                break;

            case 36:
                duration = 1;
                dotted   = true;
                break;

            case 32:
                duration = 0;
                triplet  = true;
                break;

            case 24:
                duration = 1;
                break;

            case 18:
                duration = 2;
                dotted   = true;
                break;

            case 16:
                duration = 1;
                triplet  = true;
                break;

            case 12:
                duration = 2;
                break;

            case 9:
                duration = 3;
                dotted   = true;
                break;

            case 8:
                duration = 2;
                triplet  = true;
                break;

            case 6:
                duration = 3;
                break;

            case 4:
                duration = 3;
                triplet  = true;
                break;

            case 3:
                duration = 4;
                break;

            case 2:
                duration = 4;
                triplet  = true;
                break;

            default:
                Console.WriteLine("  Warning: Rhythm Duration {0} not handled, defaulting to quarter note.", chord.Duration);
                duration = 0;
                break;
            }

            Byte flags = 0;

            if (chord.Notes.Count == 0)
            {
                flags |= REST;
            }
            if (dotted)
            {
                flags |= DOTTED_NOTE;
            }
            if (triplet)
            {
                flags |= TUPLET;
            }
            if (changeTempo)
            {
                flags |= MIX_TABLE;
            }
            if (chord.Section != null)
            {
                flags |= TEXT;
            }
            bool tapped = false;

            foreach (var kvp in chord.Notes)
            {
                if (kvp.Value.Tapped)
                {
                    tapped = true;
                }
            }
            if (chord.Popped || chord.Slapped || tapped)
            {
                flags |= BEAT_EFFECTS;
            }

            var chordTemplates = score.Tracks[trackNumber].ChordTemplates;

            if (chord.ChordId != -1 && chord.ChordId != prevChordId[trackNumber] &&
                chordTemplates.ContainsKey(chord.ChordId) &&
                chordTemplates[chord.ChordId].Name != string.Empty)
            {
                flags |= CHORD_DIAGRAM;
            }
            prevChordId[trackNumber] = chord.ChordId;

            writer.Write(flags);
            if (chord.Notes.Count == 0)
            {
                writer.Write((Byte)2);  // 2 is an actual rest, 0 is silent
            }
            writer.Write(duration);
            if (triplet)
            {
                writer.Write((Int32)3);  // declare a triplet beat
            }
            // chord diagram
            if ((flags & CHORD_DIAGRAM) != 0)
            {
                var chordTemplate = chordTemplates[chord.ChordId];
                WriteChordTemplate(chordTemplate);
            }
            // section names
            if ((flags & TEXT) != 0)
            {
                WriteDoublePrefixedString(chord.Section);
            }

            // beat effects
            if ((flags & BEAT_EFFECTS) != 0)
            {
                short effectsFlag = 0;
                if (chord.Popped || chord.Slapped || tapped)
                {
                    effectsFlag |= STRING_EFFECTS;
                }
                writer.Write(effectsFlag);
                if (tapped)
                {
                    writer.Write(TAPPING);
                }
                else if (chord.Slapped)
                {
                    writer.Write(SLAPPING);
                }
                else if (chord.Popped)
                {
                    writer.Write(POPPING);
                }
            }

            // mix table (used for changing tempo)
            if ((flags & MIX_TABLE) != 0)
            {
                for (int i = 0; i < 23; ++i)
                {
                    writer.Write((Byte)0xff);
                }
                WriteDoublePrefixedString(""); // tempo string
                writer.Write((Int32)newTempo);
                writer.Write((Byte)0);         // means new tempo takes effect immediately
                writer.Write((Byte)1);
                writer.Write((Byte)0xff);
            }

            // now write the actual notes. a flag indicates which strings are being played
            Byte stringFlags  = 0;
            int  stringOffset = 7 - numStrings;

            foreach (var kvp in chord.Notes)
            {
                stringFlags |= (Byte)(1 << (kvp.Key + stringOffset));
            }
            writer.Write(stringFlags);
            var notes = chord.Notes.Values.OrderByDescending(x => x.String);

            foreach (var note in notes)
            {
                WriteNote(note, trackNumber);
            }
            // there seem to be a few accidental ties set in the Rocksmith XMLs
            // so unset the tie status on any strings that weren't in the current chord.
            for (int i = 0; i < 6; ++i)
            {
                if (!chord.Notes.ContainsKey(i))
                {
                    tieNotes[trackNumber][i] = false;
                }
            }

            short noteTranspose = 0;

            writer.Write(noteTranspose);
        }
Пример #3
0
        static Chord CreateChord(SongChord2014 rsChord, Dictionary <int, ChordTemplate> chordTemplates, int capo)
        {
            var chord = new Chord();

            chord.Start   = rsChord.Time;
            chord.ChordId = rsChord.ChordId;
            chord.Tremolo = false;
            if (rsChord.ChordNotes != null)
            {
                foreach (var note in rsChord.ChordNotes)
                {
                    chord.Notes.Add(note.String, CreateNote(note, capo));
                }
            }
            if (chordTemplates.ContainsKey(chord.ChordId))
            {
                // need to determine chords from the chord template
                var template = chordTemplates[chord.ChordId];
                for (int i = 0; i < 6; ++i)
                {
                    if (template.Frets[i] >= 0 && !chord.Notes.ContainsKey(i))
                    {
                        var note = new Note()
                        {
                            Fret           = template.Frets[i],
                            String         = i,
                            LeftFingering  = template.Fingers[i],
                            RightFingering = -1,
                        };
                        chord.Notes.Add(i, note);
                    }
                }
            }
            if (chord.Notes.Count == 0)
            {
                Console.WriteLine("  Warning: Empty chord. Cannot find chord with chordId {0}.", chord.ChordId);
            }

            // some properties set on the chord in Rocksmith need to be passed down to the individual notes
            // and vice versa
            foreach (var kvp in chord.Notes)
            {
                if (rsChord.PalmMute != 0)
                {
                    kvp.Value.PalmMuted = true;
                }
                if (rsChord.FretHandMute != 0)
                {
                    kvp.Value.Muted = true;
                }
                if (rsChord.Accent != 0)
                {
                    kvp.Value.Accent = true;
                }
                if (kvp.Value.Tremolo)
                {
                    chord.Tremolo = true;
                }
                if (kvp.Value.Slapped)
                {
                    chord.Slapped = true;
                }
                if (kvp.Value.Popped)
                {
                    chord.Popped = true;
                }
            }

            // we will show a strum hint for all chords played with an up-stroke,
            // and a down-stroke hint for all chords with more than 3 notes (to exclude power-chords)
            //if (rsChord.Strum.ToLower() == "up")
            //    chord.BrushDirection = Chord.BrushType.Up;
            //else if (chord.Notes.Count > 3 && rsChord.Strum.ToLower() == "down")
            //    chord.BrushDirection = Chord.BrushType.Down;
            // disabled, since apparently the strum hints aren't really useful. I might have
            // misunderstood the parameter.

            return(chord);
        }
Пример #4
0
        int ExportOrFindBeat(Chord chord)
        {
            var beat = new Beat();

            beat.Id = gpif.Beats.Count;
            foreach (var note in chord.Notes)
            {
                int id = ExportOrFindNote(note.Value);
                beat.Notes.Add(id);
            }
            // there seem to be a few accidental ties set in the Rocksmith XMLs
            // so unset the tie status on any strings that weren't in the current chord.
            for (int i = 0; i < 6; ++i)
            {
                if (!chord.Notes.ContainsKey(i))
                {
                    link[i] = false;
                }
            }

            // should we display a strum hint?
            if (chord.BrushDirection != Chord.BrushType.None)
            {
                var brushProp = new Property()
                {
                    Name = "Brush"
                };
                if (chord.BrushDirection == Chord.BrushType.Down)
                {
                    brushProp.Direction = "Down";
                }
                else
                {
                    brushProp.Direction = "Up";
                }
                if (beat.Properties == null)
                {
                    beat.Properties = new List <Property>();
                }
                beat.Properties.Add(brushProp);
            }

            // tremolo picking
            if (chord.Tremolo)
            {
                // 32nd notes tremolo picking (should be appropriate)
                beat.Tremolo = "1/8";
            }

            // slap/pop notes
            if (chord.Slapped)
            {
                if (beat.Properties == null)
                {
                    beat.Properties = new List <Property>();
                }
                beat.Properties.Add(new Property()
                {
                    Name = "Slapped", Enable = new Property.EnableType()
                });
            }
            if (chord.Popped)
            {
                if (beat.Properties == null)
                {
                    beat.Properties = new List <Property>();
                }
                beat.Properties.Add(new Property()
                {
                    Name = "Popped", Enable = new Property.EnableType()
                });
            }

            // construct rhythm
            var rhythm = new Rhythm();

            rhythm.Id = gpif.Rhythms.Count;
            switch (chord.Duration)
            {
            case 192:
                rhythm.NoteValue = "Whole";
                break;

            case 168:      // should avoid this, split note instead (TODO)
                rhythm.NoteValue       = "Half";
                rhythm.AugmentationDot = new Rhythm.Dot()
                {
                    Count = 2
                };
                break;

            case 144:
                rhythm.NoteValue       = "Half";
                rhythm.AugmentationDot = new Rhythm.Dot()
                {
                    Count = 1
                };
                break;

            case 96:
                rhythm.NoteValue = "Half";
                break;

            case 84:      // should avoid this, split note instead (TODO)
                rhythm.NoteValue       = "Quarter";
                rhythm.AugmentationDot = new Rhythm.Dot()
                {
                    Count = 2
                };
                break;

            case 72:
                rhythm.NoteValue       = "Quarter";
                rhythm.AugmentationDot = new Rhythm.Dot()
                {
                    Count = 1
                };
                break;

            case 48:
                rhythm.NoteValue = "Quarter";
                break;

            case 36:
                rhythm.NoteValue       = "Eighth";
                rhythm.AugmentationDot = new Rhythm.Dot()
                {
                    Count = 1
                };
                break;

            case 32:
                rhythm.NoteValue     = "Quarter";
                rhythm.PrimaryTuplet = new Rhythm.Tuplet()
                {
                    Den = 2, Num = 3
                };
                break;

            case 24:
                rhythm.NoteValue = "Eighth";
                break;

            case 18:
                rhythm.NoteValue       = "16th";
                rhythm.AugmentationDot = new Rhythm.Dot()
                {
                    Count = 1
                };
                break;

            case 16:
                rhythm.NoteValue     = "Eighth";
                rhythm.PrimaryTuplet = new Rhythm.Tuplet()
                {
                    Den = 2, Num = 3
                };
                break;

            case 12:
                rhythm.NoteValue = "16th";
                break;

            case 9:
                rhythm.NoteValue       = "32nd";
                rhythm.AugmentationDot = new Rhythm.Dot()
                {
                    Count = 1
                };
                break;

            case 8:
                rhythm.NoteValue     = "16th";
                rhythm.PrimaryTuplet = new Rhythm.Tuplet()
                {
                    Den = 2, Num = 3
                };
                break;

            case 6:
                rhythm.NoteValue = "32nd";
                break;

            case 4:
                rhythm.NoteValue     = "32nd";
                rhythm.PrimaryTuplet = new Rhythm.Tuplet()
                {
                    Den = 2, Num = 3
                };
                break;

            case 3:
                rhythm.NoteValue = "64th";
                break;

            case 2:
                rhythm.NoteValue     = "64th";
                rhythm.PrimaryTuplet = new Rhythm.Tuplet()
                {
                    Den = 2, Num = 3
                };
                break;

            case 1:
                rhythm.NoteValue     = "128th";
                rhythm.PrimaryTuplet = new Rhythm.Tuplet()
                {
                    Den = 2, Num = 3
                };
                break;

            default:
                Console.WriteLine("  Warning: Rhythm Duration {0} not handled, defaulting to quarter note.", chord.Duration);
                rhythm.NoteValue = "Quarter";
                break;
            }
            // see if this rhythm already exists, otherwise add
            var searchRhythm = gpif.Rhythms.Find(x => x.Equals(rhythm));

            if (searchRhythm != null)
            {
                rhythm = searchRhythm;
            }
            else
            {
                gpif.Rhythms.Add(rhythm);
            }

            beat.Rhythm.Ref = rhythm.Id;

            // should we display a chord name?
            if (chord.ChordId != -1 && chord.ChordId != prevChordId)
            {
                beat.Chord = chord.ChordId.ToString();
            }
            prevChordId = chord.ChordId;

            if (chord.Section != null)
            {
                beat.FreeText = chord.Section;
            }

            // see if this beat already exists, otherwise add
            var searchBeat = gpif.Beats.Find(x => x.Equals(beat));

            if (searchBeat != null)
            {
                beat = searchBeat;
            }
            else
            {
                gpif.Beats.Add(beat);
            }

            return(beat.Id);
        }