using System; using System.Collections.Generic; using System.Linq; using Melanchall.DryWetMidi.Smf; using Melanchall.DryWetMidi.Smf.Interaction; using SBRL.Utilities; namespace MusicBoxConverter { public class MusicBoxScoreGenerator { public Vector2 offset { get; set; } = new Vector2(10, 10); public Vector2 scaleFactor { get; set; } = new Vector2(0.1f, 4f); public int holeSize { get; set; } = 5; private int trackLength; public int TrackLength { get { if (trackLength == 0) trackLength = (int)AllNotes().Max((Note arg) => arg.Time); return trackLength; } } public int MaxNoteNumber { get { // TODO: Update to get the max note number supported by the music box return AllNotes().Max((Note note) => note.NoteNumber); } } public int MinNoteNumber { get { // TODO: Update to get the min note number supported by the music box return AllNotes().Min((Note note) => note.NoteNumber); } } public MusicBox MusicBox { get; private set; } MidiFile midiFile; public MusicBoxScoreGenerator(string filename, MusicBox inMusicBox) { MusicBox = inMusicBox; midiFile = MidiFile.Read("/home/sbrl/Music/Sheets/HappyBirthday.midi"); foreach(Note note in AllNotes()) { if (!MusicBox.IsValidNote(note)) Console.Error.WriteLine($"Warning: The note {note} at {note.Time} can't be played by the {MusicBox}."); } } public void Output(string destinationFilename) { Vector2 area = new Vector2(TrackLength, MaxNoteNumber - MinNoteNumber).Multiply(scaleFactor); Vector2 size = area.Add(offset.Multiply(2)); SvgWriter svg = new SvgWriter(destinationFilename, size.X.ToString(), size.Y.ToString()); for(int i = 0; i < area.Y; i += 5) { Vector2 start = offset.Add(new Vector2(0, i * scaleFactor.Y)); svg.WriteLine(start, start.Add(new Vector2(TrackLength * scaleFactor.X, 0))); } svg.WriteRectangle(offset, area); foreach(Note note in AllNotes()) { Console.WriteLine("[{0}] {1}{2}/{3}", note.Time, note.NoteName, note.Octave, note.NoteNumber); svg.WriteCircle( new Vector2( offset.X + note.Time * scaleFactor.X, offset.Y + note.NoteNumber * scaleFactor.Y ), holeSize // radius ); } svg.Complete(); } public IEnumerable AllNotes() { foreach(TrackChunk chunk in midiFile.Chunks.OfType()) { using(NotesManager notesManager = new NotesManager(chunk.Events)) { foreach(Note note in notesManager.Notes) yield return note; } } } } }