public static double Frequency2Note(double frequency) { string dummy; return(TuningFrequency.Frequency2Note(frequency, out dummy)); }
public static double Frequency2Cents(double frequency) { double dummy; return(TuningFrequency.Frequency2Cents(frequency, out dummy)); }
/// <summary> /// Fill Arrangement 2014 from json and xml. /// </summary> /// <param name="attr"></param> /// <param name="xmlSongFile"></param> /// <param name="fixMultiTone">If set to <c>true</c> fix low bass tuning </param> /// <param name="fixLowBass">If set to <c>true</c> fix multitone exceptions </param> public Arrangement(Attributes2014 attr, string xmlSongFile, bool fixMultiTone = false, bool fixLowBass = false) { var isDirty = false; var song = Song2014.LoadFromFile(xmlSongFile); this.SongFile = new SongFile { File = "" }; this.SongXml = new SongXML { File = xmlSongFile }; //Properties Debug.Assert(attr.ArrangementType != null, "Missing information from manifest (ArrangementType)"); SetArrType(attr.ArrangementType); this.ArrangementPropeties = attr.ArrangementProperties; this.ArrangementSort = attr.ArrangementSort; this.Name = (ArrangementName)Enum.Parse(typeof(ArrangementName), attr.ArrangementName); this.ScrollSpeed = Convert.ToInt32(attr.DynamicVisualDensity.Last() * 10); this.PluckedType = (PluckedType)attr.ArrangementProperties.BassPick; this.RouteMask = (RouteMask)attr.ArrangementProperties.RouteMask; this.BonusArr = attr.ArrangementProperties.BonusArr == 1; this.Metronome = (Metronome)attr.ArrangementProperties.Metronome; this.ToneMultiplayer = attr.Tone_Multiplayer; this.Id = Guid.Parse(attr.PersistentID); this.MasterId = attr.MasterID_RDV; // Save xml comments this.XmlComments = Song2014.ReadXmlComments(xmlSongFile); // Filter out showlights\vocals if (ArrangementType != ArrangementType.Guitar && ArrangementType != ArrangementType.Bass) { return; } // Tones if (attr.Tones == null) // RS2012 { this.ToneBase = attr.Tone_Base; if (attr.Tone_A != null || attr.Tone_B != null || attr.Tone_C != null || attr.Tone_D != null) { throw new DataException("RS2012 CDLC has extraneous tone data."); } } else // RS2014 or Converter RS2012 { // TODO: optimize using common Arrangment.cs method // verify the xml Tone_ exists in tone.manifest.json foreach (var jsonTone in attr.Tones) { if (jsonTone == null) { continue; } // fix for tone.id (may not be needed/used by game) Int32 toneId = 0; // cleanup the xml arrangement file too if (jsonTone.Name.ToLower() == attr.Tone_Base.ToLower()) { this.ToneBase = song.ToneBase = attr.Tone_Base; } if (attr.Tone_A != null && jsonTone.Name.ToLower() == attr.Tone_A.ToLower()) { this.ToneA = song.ToneA = attr.Tone_A; } if (attr.Tone_B != null && jsonTone.Name.ToLower() == attr.Tone_B.ToLower()) { this.ToneB = song.ToneB = attr.Tone_B; toneId = 1; } if (attr.Tone_C != null && jsonTone.Name.ToLower() == attr.Tone_C.ToLower()) { this.ToneC = song.ToneC = attr.Tone_C; toneId = 2; } if (attr.Tone_D != null && jsonTone.Name.ToLower() == attr.Tone_D.ToLower()) { this.ToneD = song.ToneD = attr.Tone_D; toneId = 3; } // update EOF tone name and set tone id if (song.Tones != null) { foreach (var xmlTone in song.Tones) { // fix some old toolkit behavior if (xmlTone.Name == "ToneA") { xmlTone.Name = attr.Tone_A; } if (xmlTone.Name == "ToneB") { xmlTone.Name = attr.Tone_B; } if (xmlTone.Name == "ToneC") { xmlTone.Name = attr.Tone_C; } if (xmlTone.Name == "ToneD") { xmlTone.Name = attr.Tone_D; } if (xmlTone.Name.ToLower() == jsonTone.Name.ToLower() || jsonTone.Name.ToLower().EndsWith(xmlTone.Name.ToLower())) //todo: SAMENAME tone fix? { xmlTone.Name = jsonTone.Name; xmlTone.Id = toneId; } } } // song.Tones => id, name, time to apply tone is missing when song.Tones == null if (song.Tones == null && toneId > 0) { // convert the corrupt multitone to a single tone instead of throwing exception if (fixMultiTone) { song.Tones = new SongTone2014[0]; // => song.Tones.Length == 0 isDirty = true; } else { throw new InvalidDataException("Tone data is missing in CDLC and multitones will not change properly in game." + Environment.NewLine + "Please re-author XML arrangements in EOF and repair multitones name and time changes."); } } } // convert corrupt multitone to single tone and/or cleanup/repair old toolkit single tone // ToneA in single tone ODLC is null/empty if ((song.Tones == null || song.Tones.Length == 0) && !String.IsNullOrEmpty(song.ToneA)) { song.ToneA = song.ToneB = song.ToneC = String.Empty; song.ToneBase = attr.Tone_Base; this.ToneBase = attr.Tone_Base; this.ToneA = this.ToneB = this.ToneC = String.Empty; isDirty = true; } // set to standard tuning if no tuning exists if (song.Tuning == null) { song.Tuning = new TuningStrings { String0 = 0, String1 = 0, String2 = 0, String3 = 0, String4 = 0, String5 = 0 }; isDirty = true; } this.TuningStrings = song.Tuning; // NOTE: any serializing coverts abridged xml to standard xml arrangement // so only serialize if necessary to fix errors if (isDirty) { using (var stream = File.Open(xmlSongFile, FileMode.Create)) song.Serialize(stream, true); // write comments back to xml now so they are available for debugging (used for Guitar and Bass) Song2014.WriteXmlComments(xmlSongFile, XmlComments, writeNewVers: false); } // do a quick check/repair of low bass tuning, only for RS2014 bass arrangements if (fixLowBass && song.Version == "7" && this.ArrangementType == ArrangementType.Bass) { if (attr.Tuning.String0 < -4 && attr.CentOffset != -1200.0) { if (TuningFrequency.ApplyBassFix(this, fixLowBass)) { attr.CentOffset = -1200.0; // Force 220Hz song.Tuning = Song2014.LoadFromFile(xmlSongFile).Tuning; } } } } // Set Final Tuning DetectTuning(song); this.CapoFret = attr.CapoFret; if (attr.CentOffset != null) { this.TuningPitch = attr.CentOffset.Cents2Frequency(); } }