public void TestPlaylistBasics() { BmpSong song = LoadTestSong(); Assert.IsNull(song.Id); using (BmpCoffer test = this.CreateCofferManager()) { test.SaveSong(song); Assert.IsNotNull(song.Id); IPlaylist playlist = test.CreatePlaylist(PLAYLIST_NAME); Assert.IsNotNull(playlist); Assert.IsTrue(playlist is BmpPlaylistDecorator); Assert.AreEqual(PLAYLIST_NAME, playlist.GetName()); // Internal things... BmpPlaylist backingData = ((BmpPlaylistDecorator)playlist).GetBmpPlaylist(); Assert.IsNull(backingData.Id); playlist.Add(song); test.SavePlaylist(playlist); Assert.IsNotNull(backingData.Id); IPlaylist result = test.GetPlaylist(PLAYLIST_NAME); Assert.IsNotNull(result); Assert.AreEqual(backingData.Id, ((BmpPlaylistDecorator)playlist).GetBmpPlaylist().Id); } }
public void TestAddInject() { BmpSong songA = new BmpSong() { Id = ObjectId.NewObjectId() }; BmpSong songB = new BmpSong() { Id = ObjectId.NewObjectId() }; BmpSong songC = new BmpSong() { Id = ObjectId.NewObjectId() }; BmpPlaylistDecorator test = CreateTestPlaylist(); var objRef = test.GetBmpPlaylist(); ((IPlaylist)test).Add(songA); ((IPlaylist)test).Add(songB); Assert.AreEqual(2, objRef.Songs.Count); Assert.AreSame(songA, objRef.Songs[0]); Assert.AreSame(songB, objRef.Songs[1]); ((IPlaylist)test).Add(1, songC); Assert.AreEqual(3, objRef.Songs.Count); Assert.AreSame(songA, objRef.Songs[0]); Assert.AreSame(songC, objRef.Songs[1]); Assert.AreSame(songB, objRef.Songs[2]); }
public SongEditorViewModel(BmpSong bmpSong) { _currentSong = bmpSong; TrackContainers = new(bmpSong.TrackContainers .SelectMany(container => container.Value.ConfigContainers) .Select((t, i) => new ConfigContainerViewModel(t, $"Config {i}"))); }
/// <summary> /// This saves a song. /// </summary> /// <param name="song"></param> /// <exception cref="BmpCofferException">This is thrown if a title conflict occurs on save.</exception> public void SaveSong(BmpSong song) { if (song == null) { throw new ArgumentNullException(); } var songCol = this.GetSongCollection(); try { if (song.Id == null) { song.Id = ObjectId.NewObjectId(); songCol.Insert(song); } else { songCol.Update(song); } } catch (LiteException e) { throw new BmpCofferException(e.Message, e); } }
///<inheritdoc/> void IPlaylist.Move(int sourceIdx, int targetIdx) { List <BmpSong> contents = this.target.Songs; BmpSong moveMe = contents[sourceIdx]; contents.RemoveAt(sourceIdx); contents.Insert(targetIdx, moveMe); }
public void TestSongBasics() { BmpSong song = LoadTestSong(); Assert.IsNull(song.Id); using (BmpCoffer test = this.CreateCofferManager()) { test.SaveSong(song); Assert.IsNotNull(song.Id); BmpSong resultTitle = test.GetSong(song.Title); Assert.AreEqual(song.Id, resultTitle.Id); } }
public void TestSongListing() { BmpSong song = LoadTestSong(); Assert.IsNull(song.Id); using (BmpCoffer test = this.CreateCofferManager()) { test.SaveSong(song); Assert.IsNotNull(song.Id); IList <string> resultAll = test.GetSongTitles(); Assert.AreEqual(1, resultAll.Count); Assert.AreEqual(song.Title, resultAll[0]); } }
public void TestAddAppend() { BmpSong songA = new BmpSong() { Id = ObjectId.NewObjectId() }; BmpPlaylistDecorator test = CreateTestPlaylist(); var objRef = test.GetBmpPlaylist(); Assert.AreEqual(0, objRef.Songs.Count); ((IPlaylist)test).Add(songA); Assert.AreEqual(1, objRef.Songs.Count); Assert.AreSame(songA, objRef.Songs[0]); }
public void TestDuplicateSong() { BmpSong songA = LoadTestSong(); Assert.IsNull(songA.Id); BmpSong songB = LoadTestSong(); Assert.IsNull(songB.Id); using (BmpCoffer test = this.CreateCofferManager()) { test.SaveSong(songA); Assert.IsNotNull(songA.Id); test.SaveSong(songB); } }
/// <summary> /// Tag matching algorithm. /// </summary> /// <param name="search"></param> /// <param name="song"></param> /// <returns></returns> private static bool TagMatches(string search, BmpSong song) { bool ret = false; var tags = song.Tags; if (tags != null && tags.Count > 0) { for (int i = 0; i < tags.Count; ++i) { if (string.Equals(search, tags[i], StringComparison.OrdinalIgnoreCase)) { ret = true; break; } } } return(ret); }
public void TestDuplicatePlaylist() { BmpSong song = LoadTestSong(); Assert.IsNull(song.Id); using (BmpCoffer test = this.CreateCofferManager()) { test.SaveSong(song); Assert.IsNotNull(song.Id); IPlaylist playlistA = test.CreatePlaylist(PLAYLIST_NAME); Assert.IsNotNull(playlistA); IPlaylist playlistB = test.CreatePlaylist(PLAYLIST_NAME); Assert.IsNotNull(playlistB); test.SavePlaylist(playlistA); test.SavePlaylist(playlistB); } }
public void TestPlaylistFromTag() { BmpSong song = LoadTestSong(); Assert.IsNull(song.Id); song.Tags.Add(TEST_SONG_TAG_A); song.Tags.Add(TEST_SONG_TAG_B); using (BmpCoffer test = this.CreateCofferManager()) { test.SaveSong(song); Assert.IsNotNull(song.Id); IPlaylist tagPlaylist = test.CreatePlaylistFromTag(TEST_SONG_TAG_A); Assert.IsNotNull(tagPlaylist); List <BmpSong> allTags = new List <BmpSong>(); foreach (BmpSong entry in tagPlaylist) { allTags.Add(entry); } Assert.AreEqual(1, allTags.Count); Assert.AreEqual(song.Id, allTags[0].Id); tagPlaylist = test.CreatePlaylistFromTag(TEST_SONG_TAG_B); Assert.IsNotNull(tagPlaylist); allTags.Clear(); foreach (BmpSong entry in tagPlaylist) { allTags.Add(entry); } Assert.AreEqual(1, allTags.Count); Assert.AreEqual(song.Id, allTags[0].Id); } }
public void TestPlaylistListing() { BmpSong song = LoadTestSong(); Assert.IsNull(song.Id); using (BmpCoffer test = this.CreateCofferManager()) { test.SaveSong(song); Assert.IsNotNull(song.Id); IPlaylist playlist = test.CreatePlaylist(PLAYLIST_NAME); Assert.IsNotNull(playlist); playlist.Add(song); test.SavePlaylist(playlist); IList <string> names = test.GetPlaylistNames(); Assert.AreEqual(1, names.Count); Assert.AreEqual(playlist.GetName(), names[0]); } }
/// <summary> /// /// </summary> /// <param name="trackChunk"></param> /// <param name="trackNumber"></param> /// <param name="song"></param> /// <returns></returns> internal static Dictionary <long, ConfigContainer> ReadConfigs(this TrackChunk trackChunk, int trackNumber, BmpSong song) { var configContainers = new Dictionary <long, ConfigContainer>(); if (trackChunk.GetNotes().Count == 0 && trackChunk.GetTimedEvents().All(x => x.Event.EventType != MidiEventType.Lyric)) { BmpLog.I(BmpLog.Source.Transmogrify, "Skipping track " + trackNumber + " as it contains no notes and contains no lyric events."); return(configContainers); } var trackName = (trackChunk.Events.OfType <SequenceTrackNameEvent>().FirstOrDefault()?.Text ?? "").Replace(" ", "").ToLower(); if (trackName.Contains("ignore")) { BmpLog.I(BmpLog.Source.Transmogrify, "Skipping track " + trackNumber + " as the track title contains \"Ignore\""); return(configContainers); } var groups = trackName.Split('|'); var modifier = new Regex(@"^([A-Za-z0-9]+)([-+]\d)?"); for (var groupCounter = 0; groupCounter < groups.Length; groupCounter++) { var configContainer = new ConfigContainer(); var fields = groups[groupCounter].Split(';'); if (fields.Length == 0) { continue; } // bmp 2.x style group name if (fields[0].StartsWith("vst:") || fields[0].Equals("lyrics")) { var subfields = fields[0].Split(':'); switch (subfields[0]) { case "vst" when subfields.Length < 2: BmpLog.W(BmpLog.Source.Transmogrify, "Skipping VST on track " + trackNumber + " due to the configuration not specifying a tone."); continue; case "vst": var manualToneConfig = (VSTProcessorConfig)(configContainer.ProcessorConfig = new VSTProcessorConfig { Track = trackNumber }); manualToneConfig.InstrumentTone = InstrumentTone.Parse(subfields[1]); if (manualToneConfig.InstrumentTone.Equals(InstrumentTone.None)) { BmpLog.W(BmpLog.Source.Transmogrify, "Skipping VST on track " + trackNumber + " due to the configuration specifying an invalid tone."); continue; } if (subfields.Length > 2) { var shifts = subfields[2].Split(','); foreach (var shift in shifts) { var toneIndexAndOctaveRange = modifier.Match(shift); if (!toneIndexAndOctaveRange.Success) { BmpLog.W(BmpLog.Source.Transmogrify, "Skipping invalid VST octave setting \"" + shift + "\" on track " + trackNumber); continue; } if (!toneIndexAndOctaveRange.Groups[1].Success) { BmpLog.W(BmpLog.Source.Transmogrify, "Skipping invalid VST octave setting \"" + shift + "\" on track " + trackNumber + " because \"" + toneIndexAndOctaveRange.Groups[1].Value + "\" is not a valid tone number"); continue; } if (!int.TryParse(toneIndexAndOctaveRange.Groups[1].Value, out var toneIndex) || toneIndex < 0 || toneIndex > 4) { BmpLog.W(BmpLog.Source.Transmogrify, "Skipping invalid VST octave setting \"" + shift + "\" on track " + trackNumber + " because \"" + toneIndexAndOctaveRange.Groups[1].Value + "\" is not a valid tone number"); continue; } var octaveRange = OctaveRange.C3toC6; if (toneIndexAndOctaveRange.Groups[2].Success) { octaveRange = OctaveRange.Parse(toneIndexAndOctaveRange.Groups[2].Value); } if (octaveRange.Equals(OctaveRange.Invalid)) { octaveRange = OctaveRange.C3toC6; } manualToneConfig.OctaveRanges[toneIndex] = octaveRange; } } ParseAdditionalOptions(trackNumber, manualToneConfig, song, fields); BmpLog.I(BmpLog.Source.Transmogrify, "Found VST Config Group with on track " + manualToneConfig.Track + " ;bards=" + manualToneConfig.PlayerCount + ";include=" + string.Join(",", manualToneConfig.IncludedTracks)); configContainers.Add(groupCounter, configContainer); continue; case "lyrics": var lyricConfig = (LyricProcessorConfig)(configContainer.ProcessorConfig = new LyricProcessorConfig { Track = trackNumber }); ParseAdditionalOptions(trackNumber, lyricConfig, song, fields); BmpLog.I(BmpLog.Source.Transmogrify, "Found Lyric Config on track " + lyricConfig.Track + " ;bards=" + lyricConfig.PlayerCount + ";include=" + string.Join(",", lyricConfig.IncludedTracks)); configContainers.Add(groupCounter, configContainer); continue; } } // bmp 1.x style group name else { var classicConfig = (ClassicProcessorConfig)(configContainer.ProcessorConfig = new ClassicProcessorConfig { Track = trackNumber }); var instrumentAndOctaveRange = modifier.Match(fields[0]); if (!instrumentAndOctaveRange.Success) { continue; // Invalid Instrument name. } if (instrumentAndOctaveRange.Groups[1].Success) { classicConfig.Instrument = Instrument.Parse(instrumentAndOctaveRange.Groups[1].Value); } if (classicConfig.Instrument.Equals(Instrument.None)) { continue; // Invalid Instrument name. } if (instrumentAndOctaveRange.Groups[2].Success) { classicConfig.OctaveRange = OctaveRange.Parse(instrumentAndOctaveRange.Groups[2].Value); } if (classicConfig.OctaveRange.Equals(OctaveRange.Invalid)) { classicConfig.OctaveRange = OctaveRange.C3toC6; } ParseAdditionalOptions(trackNumber, classicConfig, song, fields); BmpLog.I(BmpLog.Source.Transmogrify, "Found Classic Config Instrument " + classicConfig.Instrument.Name + " OctaveRange " + classicConfig.OctaveRange.Name + " on track " + classicConfig.Track + " ;bards=" + classicConfig.PlayerCount + ";include=" + string.Join(",", classicConfig.IncludedTracks)); configContainers.Add(groupCounter, configContainer); } } if (configContainers.Count == 0) { BmpLog.I(BmpLog.Source.Transmogrify, "Found 0 configurations on track " + trackNumber + ", and the keyword \"Ignore\" is not in the track title. Adding a default harp."); configContainers.Add(0, new ConfigContainer { ProcessorConfig = new ClassicProcessorConfig { Track = trackNumber } }); } return(configContainers); }
internal ManualToneProcessor(ManualToneProcessorConfig processorConfig, BmpSong song) : base(song) { ProcessorConfig = processorConfig; }
internal DrumToneProcessor(DrumToneProcessorConfig processorConfig, BmpSong song) : base(song) { ProcessorConfig = processorConfig; }
/// <inheritdoc /> void IPlaylist.Remove(BmpSong song) { this.target.Songs.Remove(song); }
private static BmpSong LoadTestSong() => BmpSong.OpenMidiFile(TEST_SONG_FILENAME).GetAwaiter().GetResult();
protected BaseProcessor(BmpSong song) { Song = song; }
internal OctaveToneProcessor(OctaveToneProcessorConfig processorConfig, BmpSong song) : base(song) { ProcessorConfig = processorConfig; }
internal ClassicProcessor(ClassicProcessorConfig processorConfig, BmpSong song) : base(song) { ProcessorConfig = processorConfig; }
internal AutoToneProcessor(AutoToneProcessorConfig processorConfig, BmpSong song) : base(song) { ProcessorConfig = processorConfig; }
internal NoteToneProcessor(NoteToneProcessorConfig processorConfig, BmpSong song) : base(song) { ProcessorConfig = processorConfig; }
internal LyricProcessor(LyricProcessorConfig processorConfig, BmpSong song) : base(song) { ProcessorConfig = processorConfig; }
///<inheritdoc/> void IPlaylist.Add(BmpSong song) { this.target.Songs.Add(song); }
/// <summary> /// Parses tracks to merge in, and bards to load balance distribute to. /// </summary> /// <param name="trackNumber"></param> /// <param name="processorConfig"></param> /// <param name="song"></param> /// <param name="fields"></param> private static void ParseAdditionalOptions(int trackNumber, IProcessorConfig processorConfig, BmpSong song, IReadOnlyList <string> fields) { for (var fieldCounter = 1; fieldCounter < fields.Count; fieldCounter++) { if (fields[fieldCounter].StartsWith("include=")) { var tracksToMerge = fields[fieldCounter].Remove(0, 8).Split(','); foreach (var trackToMerge in tracksToMerge) { if (int.TryParse(trackToMerge, out var value) && value != trackNumber && value > -1 && value < song.TrackContainers.Count) { processorConfig.IncludedTracks.Add(value); } } } else if (fields[fieldCounter].StartsWith("bards=") && int.TryParse(fields[fieldCounter].Remove(0, 6), out var value) && value > 0 && value < 17) { processorConfig.PlayerCount = value; } } }
///<inheritdoc/> void IPlaylist.Add(int idx, BmpSong song) { this.target.Songs.Insert(idx, song); }
internal static async Task <(MidiFile, Dictionary <int, Dictionary <long, string> >)> GetSynthMidi(this BmpSong song) { var file = new MidiFile { Division = 600 }; var events = new AlphaSynthMidiFileHandler(file); events.AddTempo(0, 100); var trackCounter = byte.MinValue; var veryLast = 0L; var midiFile = await song.GetProcessedMidiFile(); var trackChunks = midiFile.GetTrackChunks().ToList(); var lyrics = new Dictionary <int, Dictionary <long, string> >(); var lyricNum = 0; foreach (var trackChunk in trackChunks) { var options = trackChunk.Events.OfType <SequenceTrackNameEvent>().First().Text.Split(':'); switch (options[0]) { case "lyric": { if (!lyrics.ContainsKey(lyricNum)) { lyrics.Add(lyricNum, new Dictionary <long, string>(int.Parse(options[1]))); } foreach (var lyric in trackChunk.GetTimedEvents().Where(x => x.Event.EventType == MidiEventType.Lyric)) { lyrics[lyricNum].Add(lyric.Time, ((LyricEvent)lyric.Event).Text); } lyricNum++; break; } case "tone": { var tone = InstrumentTone.Parse(options[1]); foreach (var note in trackChunk.GetNotes()) { var instrument = tone.GetInstrumentFromChannel(note.Channel); var noteNum = note.NoteNumber; var dur = (int)MinimumLength(instrument, noteNum - 48, note.Length); var time = (int)note.Time; events.AddProgramChange(trackCounter, time, trackCounter, (byte)instrument.MidiProgramChangeCode); events.AddNote(trackCounter, time, dur, noteNum, DynamicValue.FFF, trackCounter); if (trackCounter == byte.MaxValue) { trackCounter = byte.MinValue; } else { trackCounter++; } if (time + dur > veryLast) { veryLast = time + dur; } } break; } } } events.FinishTrack(byte.MaxValue, (byte)veryLast); return(file, lyrics); }
internal VSTProcessor(VSTProcessorConfig processorConfig, BmpSong song) : base(song) { ProcessorConfig = processorConfig; }
/// <summary> /// /// </summary> /// <param name="trackChunk"></param> /// <param name="trackNumber"></param> /// <param name="song"></param> /// <returns></returns> internal static Dictionary <long, ConfigContainer> ReadConfigs(this TrackChunk trackChunk, int trackNumber, BmpSong song) { var configContainers = new Dictionary <long, ConfigContainer>(); if (trackChunk.GetNotes().Count == 0 && trackChunk.GetTimedEvents().All(x => x.Event.EventType != MidiEventType.Lyric)) { BmpLog.I(BmpLog.Source.Transmogrify, "Skipping track " + trackNumber + " as it contains no notes and contains no lyric events."); return(configContainers); } var trackName = (trackChunk.Events.OfType <SequenceTrackNameEvent>().FirstOrDefault()?.Text ?? "").Replace(" ", "").ToLower(); if (trackName.Contains("ignore")) { BmpLog.I(BmpLog.Source.Transmogrify, "Skipping track " + trackNumber + " as the track title contains \"Ignore\""); return(configContainers); } var groups = trackName.Split('|'); var modifier = new Regex(@"^([A-Za-z0-9]+)([-+]\d)?"); for (var groupCounter = 0; groupCounter < groups.Length; groupCounter++) { var configContainer = new ConfigContainer(); var fields = groups[groupCounter].Split(';'); if (fields.Length == 0) { continue; } // bmp 2.x style group name if (fields[0].StartsWith("manualtone:") || fields[0].StartsWith("notetone:") || fields[0].StartsWith("autotone:") || fields[0].StartsWith("drumtone:") || fields[0].Equals("drumtone") || fields[0].StartsWith("octavetone") || fields[0].Equals("lyric")) { var subfields = fields[0].Split(':'); switch (subfields[0]) { case "manualtone" when subfields.Length < 2: BmpLog.W(BmpLog.Source.Transmogrify, "Skipping ManualTone on track " + trackNumber + " due to the configuration not specifying a tone."); continue; case "manualtone": var manualToneConfig = (ManualToneProcessorConfig)(configContainer.ProcessorConfig = new ManualToneProcessorConfig { Track = trackNumber }); manualToneConfig.InstrumentTone = InstrumentTone.Parse(subfields[1]); if (manualToneConfig.InstrumentTone.Equals(InstrumentTone.None)) { BmpLog.W(BmpLog.Source.Transmogrify, "Skipping ManualTone on track " + trackNumber + " due to the configuration specifying an invalid tone."); continue; } if (subfields.Length > 2) { var shifts = subfields[2].Split(','); foreach (var shift in shifts) { var toneIndexAndOctaveRange = modifier.Match(shift); if (!toneIndexAndOctaveRange.Success) { BmpLog.W(BmpLog.Source.Transmogrify, "Skipping invalid ManualTone octave setting \"" + shift + "\" on track " + trackNumber); continue; } if (!toneIndexAndOctaveRange.Groups[1].Success) { BmpLog.W(BmpLog.Source.Transmogrify, "Skipping invalid ManualTone octave setting \"" + shift + "\" on track " + trackNumber + " because \"" + toneIndexAndOctaveRange.Groups[1].Value + "\" is not a valid tone number"); continue; } if (!int.TryParse(toneIndexAndOctaveRange.Groups[1].Value, out var toneIndex) || toneIndex < 0 || toneIndex > 4) { BmpLog.W(BmpLog.Source.Transmogrify, "Skipping invalid ManualTone octave setting \"" + shift + "\" on track " + trackNumber + " because \"" + toneIndexAndOctaveRange.Groups[1].Value + "\" is not a valid tone number"); continue; } var octaveRange = OctaveRange.C3toC6; if (toneIndexAndOctaveRange.Groups[2].Success) { octaveRange = OctaveRange.Parse(toneIndexAndOctaveRange.Groups[2].Value); } if (octaveRange.Equals(OctaveRange.Invalid)) { octaveRange = OctaveRange.C3toC6; } manualToneConfig.OctaveRanges[toneIndex] = octaveRange; } } ParseAdditionalOptions(trackNumber, manualToneConfig, song, fields); BmpLog.I(BmpLog.Source.Transmogrify, "Found ManualTone Config Group with on track " + manualToneConfig.Track + " ;bards=" + manualToneConfig.PlayerCount + ";include=" + string.Join(",", manualToneConfig.IncludedTracks)); configContainers.Add(groupCounter, configContainer); continue; case "notetone" when subfields.Length < 2: BmpLog.W(BmpLog.Source.Transmogrify, "Skipping NoteTone on track " + trackNumber + " due to the configuration not specifying a tone."); continue; case "notetone": { var noteToneConfig = (NoteToneProcessorConfig)(configContainer.ProcessorConfig = new NoteToneProcessorConfig { Track = trackNumber }); noteToneConfig.InstrumentTone = InstrumentTone.Parse(subfields[1]); if (noteToneConfig.InstrumentTone.Equals(InstrumentTone.None)) { BmpLog.W(BmpLog.Source.Transmogrify, "Skipping NoteTone on track " + trackNumber + " due to the configuration specifying an invalid tone."); continue; } var noteToneSubConfigurations = 0; if (subfields.Length > 2) { subfields = subfields.Skip(2).ToArray(); foreach (var mapping in subfields) { var split = mapping.Split(','); if (split.Length != 3) { BmpLog.W(BmpLog.Source.Transmogrify, "Skipping invalid NoteTone mapping \"" + mapping + "\" on track " + trackNumber); continue; } if (!int.TryParse(split[0], out var sourceNote) || sourceNote > 120 || sourceNote < 12) { BmpLog.W(BmpLog.Source.Transmogrify, "Skipping invalid NoteTone mapping \"" + mapping + "\" on track " + trackNumber + " because source note \"" + split[0] + "\" is more then 120 or less then 12"); continue; } if (!int.TryParse(split[1], out var toneIndex) || toneIndex < -1 || toneIndex > 4 || (toneIndex == 0 && noteToneConfig.InstrumentTone.Tone0.Equals(Instrument.None)) || (toneIndex == 1 && noteToneConfig.InstrumentTone.Tone1.Equals(Instrument.None)) || (toneIndex == 2 && noteToneConfig.InstrumentTone.Tone2.Equals(Instrument.None)) || (toneIndex == 3 && noteToneConfig.InstrumentTone.Tone3.Equals(Instrument.None)) || (toneIndex == 4 && noteToneConfig.InstrumentTone.Tone4.Equals(Instrument.None))) { BmpLog.W(BmpLog.Source.Transmogrify, "Skipping invalid NoteTone mapping \"" + mapping + "\" on track " + trackNumber + " because \"" + split[1] + "\" is not a valid tone number for Tone " + noteToneConfig.InstrumentTone.Name); continue; } if (!int.TryParse(split[2], out var destinationNote) || destinationNote < -1 || destinationNote > 36) { BmpLog.W(BmpLog.Source.Transmogrify, "Skipping invalid NoteTone mapping \"" + mapping + "\" on track " + trackNumber + " because destination note \"" + split[2] + "\" is more then 36 or less then -1"); continue; } noteToneConfig.Mapper[sourceNote] = (toneIndex, destinationNote); noteToneSubConfigurations++; } } if (noteToneSubConfigurations == 0) { BmpLog.W(BmpLog.Source.Transmogrify, "Skipping NoteTone on track " + trackNumber + " because no mappings are specified."); continue; } ParseAdditionalOptions(trackNumber, noteToneConfig, song, fields); BmpLog.I(BmpLog.Source.Transmogrify, "Found NoteTone Config Group " + noteToneConfig.InstrumentTone.Name + " with " + noteToneSubConfigurations + " mappings on track " + noteToneConfig.Track + " ;bards=" + noteToneConfig.PlayerCount + ";include=" + string.Join(",", noteToneConfig.IncludedTracks)); configContainers.Add(groupCounter, configContainer); continue; } case "octavetone" when subfields.Length < 2: BmpLog.W(BmpLog.Source.Transmogrify, "Skipping OctaveTone on track " + trackNumber + " due to the configuration not specifying a tone."); continue; case "octavetone": var octaveToneConfig = (OctaveToneProcessorConfig)(configContainer.ProcessorConfig = new OctaveToneProcessorConfig { Track = trackNumber }); octaveToneConfig.InstrumentTone = InstrumentTone.Parse(subfields[1]); if (octaveToneConfig.InstrumentTone.Equals(InstrumentTone.None)) { BmpLog.W(BmpLog.Source.Transmogrify, "Skipping OctaveTone on track " + trackNumber + " due to the configuration specifying an invalid tone."); continue; } var octaveToneSubConfigurations = 0; if (subfields.Length > 2) { subfields = subfields.Skip(2).ToArray(); foreach (var mapping in subfields) { var split = mapping.Split(','); if (split.Length != 3) { BmpLog.W(BmpLog.Source.Transmogrify, "Skipping invalid OctaveTone mapping \"" + mapping + "\" on track " + trackNumber); continue; } if (!int.TryParse(split[0], out var sourceOctave) || sourceOctave > 8 || sourceOctave < 0) { BmpLog.W(BmpLog.Source.Transmogrify, "Skipping invalid OctaveTone mapping \"" + mapping + "\" on track " + trackNumber + " because source octave \"" + split[0] + "\" is more then 8 or less then 0"); continue; } if (!int.TryParse(split[1], out var toneIndex) || toneIndex < -1 || toneIndex > 4 || (toneIndex == 0 && octaveToneConfig.InstrumentTone.Tone0.Equals(Instrument.None)) || (toneIndex == 1 && octaveToneConfig.InstrumentTone.Tone1.Equals(Instrument.None)) || (toneIndex == 2 && octaveToneConfig.InstrumentTone.Tone2.Equals(Instrument.None)) || (toneIndex == 3 && octaveToneConfig.InstrumentTone.Tone3.Equals(Instrument.None)) || (toneIndex == 4 && octaveToneConfig.InstrumentTone.Tone4.Equals(Instrument.None))) { BmpLog.W(BmpLog.Source.Transmogrify, "Skipping invalid OctaveTone mapping \"" + mapping + "\" on track " + trackNumber + " because \"" + split[1] + "\" is not a valid tone number for Tone " + octaveToneConfig.InstrumentTone.Name); continue; } if (!int.TryParse(split[2], out var destinationOctave) || destinationOctave < -1 || destinationOctave > 3) { BmpLog.W(BmpLog.Source.Transmogrify, "Skipping invalid OctaveTone mapping \"" + mapping + "\" on track " + trackNumber + " because destination octave \"" + split[2] + "\" is more then 3 or less then -1"); continue; } octaveToneConfig.Mapper[sourceOctave] = (toneIndex, destinationOctave); octaveToneSubConfigurations++; } } if (octaveToneSubConfigurations == 0) { BmpLog.W(BmpLog.Source.Transmogrify, "Skipping OctaveTone on track " + trackNumber + " because no mappings are specified."); continue; } ParseAdditionalOptions(trackNumber, octaveToneConfig, song, fields); BmpLog.I(BmpLog.Source.Transmogrify, "Found OctaveTone Config Group " + octaveToneConfig.InstrumentTone.Name + " with " + octaveToneSubConfigurations + " mappings on track " + octaveToneConfig.Track + " ;bards=" + octaveToneConfig.PlayerCount + ";include=" + string.Join(",", octaveToneConfig.IncludedTracks)); configContainers.Add(groupCounter, configContainer); continue; case "autotone" when subfields.Length < 2: BmpLog.W(BmpLog.Source.Transmogrify, "Skipping AutoTone on track " + trackNumber + " due to the configuration not specifying an autotone group."); continue; case "autotone": { var autoToneConfig = (AutoToneProcessorConfig)(configContainer.ProcessorConfig = new AutoToneProcessorConfig { Track = trackNumber }); var instrumentAndOctaveRange = modifier.Match(subfields[1]); if (!instrumentAndOctaveRange.Success) { BmpLog.W(BmpLog.Source.Transmogrify, "Skipping AutoTone on track " + trackNumber + " due to the configuration specifying an invalid autotone group."); continue; } if (instrumentAndOctaveRange.Groups[1].Success) { autoToneConfig.AutoToneInstrumentGroup = AutoToneInstrumentGroup.Parse(instrumentAndOctaveRange.Groups[1].Value); } if (autoToneConfig.AutoToneInstrumentGroup.Equals(AutoToneInstrumentGroup.Invalid)) { BmpLog.W(BmpLog.Source.Transmogrify, "Skipping AutoTone on track " + trackNumber + " due to the configuration specifying an invalid autotone group."); continue; } if (instrumentAndOctaveRange.Groups[2].Success) { autoToneConfig.AutoToneOctaveRange = AutoToneOctaveRange.Parse(instrumentAndOctaveRange.Groups[2].Value); } if (autoToneConfig.AutoToneOctaveRange.Equals(AutoToneOctaveRange.Invalid)) { autoToneConfig.AutoToneOctaveRange = AutoToneOctaveRange.C2toC7; } ParseAdditionalOptions(trackNumber, autoToneConfig, song, fields); BmpLog.I(BmpLog.Source.Transmogrify, "Found AutoTone Config Group " + autoToneConfig.AutoToneInstrumentGroup.Name + " OctaveRange " + autoToneConfig.AutoToneOctaveRange.Name + " on track " + autoToneConfig.Track + " ;bards=" + autoToneConfig.PlayerCount + ";include=" + string.Join(",", autoToneConfig.IncludedTracks)); configContainers.Add(groupCounter, configContainer); continue; } case "drumtone": var drumToneConfig = (DrumToneProcessorConfig)(configContainer.ProcessorConfig = new DrumToneProcessorConfig { Track = trackNumber }); var drumToneSubConfigurations = 0; if (subfields.Length > 1) { subfields = subfields.Skip(1).ToArray(); foreach (var mapping in subfields) { var split = mapping.Split(','); if (split.Length != 3) { BmpLog.W(BmpLog.Source.Transmogrify, "Skipping invalid DrumTone mapping \"" + mapping + "\" on track " + trackNumber); continue; } if (!int.TryParse(split[0], out var sourceNote) || sourceNote > 87 || sourceNote < 27) { BmpLog.W(BmpLog.Source.Transmogrify, "Skipping invalid DrumTone mapping \"" + mapping + "\" on track " + trackNumber + " because source note \"" + split[0] + "\" is more then 87 or less then 27"); continue; } if (!int.TryParse(split[1], out var toneIndex) || toneIndex < -1 || toneIndex > 4 || (toneIndex == 0 && InstrumentTone.Drums.Tone0.Equals(Instrument.None)) || (toneIndex == 1 && InstrumentTone.Drums.Tone1.Equals(Instrument.None)) || (toneIndex == 2 && InstrumentTone.Drums.Tone2.Equals(Instrument.None)) || (toneIndex == 3 && InstrumentTone.Drums.Tone3.Equals(Instrument.None)) || (toneIndex == 4 && InstrumentTone.Drums.Tone4.Equals(Instrument.None))) { BmpLog.W(BmpLog.Source.Transmogrify, "Skipping invalid DrumTone mapping \"" + mapping + "\" on track " + trackNumber + " because \"" + split[1] + "\" is not a valid tone number for Tone " + InstrumentTone.Drums.Name); continue; } if (!int.TryParse(split[2], out var destinationNote) || destinationNote < -1 || destinationNote > 36) { BmpLog.W(BmpLog.Source.Transmogrify, "Skipping invalid DrumTone mapping \"" + mapping + "\" on track " + trackNumber + " because destination note \"" + split[2] + "\" is more then 36 or less then -1"); continue; } drumToneConfig.Mapper[sourceNote] = (toneIndex, destinationNote); drumToneSubConfigurations++; } } ParseAdditionalOptions(trackNumber, drumToneConfig, song, fields); BmpLog.I(BmpLog.Source.Transmogrify, "Found DrumTone Config Group with " + drumToneSubConfigurations + " override mappings on track " + drumToneConfig.Track + " ;bards=" + drumToneConfig.PlayerCount + ";include=" + string.Join(",", drumToneConfig.IncludedTracks)); configContainers.Add(groupCounter, configContainer); continue; case "lyric": var lyricConfig = (LyricProcessorConfig)(configContainer.ProcessorConfig = new LyricProcessorConfig { Track = trackNumber }); ParseAdditionalOptions(trackNumber, lyricConfig, song, fields); BmpLog.I(BmpLog.Source.Transmogrify, "Found Lyric Config on track " + lyricConfig.Track + " ;bards=" + lyricConfig.PlayerCount + ";include=" + string.Join(",", lyricConfig.IncludedTracks)); configContainers.Add(groupCounter, configContainer); continue; } } // bmp 1.x style group name else { var classicConfig = (ClassicProcessorConfig)(configContainer.ProcessorConfig = new ClassicProcessorConfig { Track = trackNumber }); var instrumentAndOctaveRange = modifier.Match(fields[0]); if (!instrumentAndOctaveRange.Success) { continue; // Invalid Instrument name. } if (instrumentAndOctaveRange.Groups[1].Success) { classicConfig.Instrument = Instrument.Parse(instrumentAndOctaveRange.Groups[1].Value); } if (classicConfig.Instrument.Equals(Instrument.None)) { continue; // Invalid Instrument name. } if (instrumentAndOctaveRange.Groups[2].Success) { classicConfig.OctaveRange = OctaveRange.Parse(instrumentAndOctaveRange.Groups[2].Value); } if (classicConfig.OctaveRange.Equals(OctaveRange.Invalid)) { classicConfig.OctaveRange = OctaveRange.C3toC6; } ParseAdditionalOptions(trackNumber, classicConfig, song, fields); BmpLog.I(BmpLog.Source.Transmogrify, "Found Classic Config Instrument " + classicConfig.Instrument.Name + " OctaveRange " + classicConfig.OctaveRange.Name + " on track " + classicConfig.Track + " ;bards=" + classicConfig.PlayerCount + ";include=" + string.Join(",", classicConfig.IncludedTracks)); configContainers.Add(groupCounter, configContainer); } } if (configContainers.Count == 0) { BmpLog.I(BmpLog.Source.Transmogrify, "Found 0 configurations on track " + trackNumber + ", and the keyword \"Ignore\" is not in the track title. Adding a default AutoTone."); configContainers.Add(0, new ConfigContainer { ProcessorConfig = new AutoToneProcessorConfig { Track = trackNumber } }); } return(configContainers); }