You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
97 lines
2.7 KiB
97 lines
2.7 KiB
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<Note> AllNotes() |
|
{ |
|
foreach(TrackChunk chunk in midiFile.Chunks.OfType<TrackChunk>()) |
|
{ |
|
using(NotesManager notesManager = new NotesManager(chunk.Events)) |
|
{ |
|
foreach(Note note in notesManager.Notes) |
|
yield return note; |
|
} |
|
} |
|
} |
|
} |
|
}
|
|
|