MusicBoxConverter/MusicBoxConverter/MusicBoxScoreGenerator.cs

122 lines
3.0 KiB
C#
Raw Normal View History

using System;
2017-11-30 23:03:55 +00:00
using System.Collections.Generic;
using System.Linq;
using Melanchall.DryWetMidi.Smf;
using Melanchall.DryWetMidi.Smf.Interaction;
2017-11-30 23:03:55 +00:00
using SBRL.Utilities;
namespace MusicBoxConverter
{
2017-12-02 19:47:40 +00:00
public class MusicBoxScoreGenerator
{
2017-12-04 12:38:15 +00:00
public bool Debug { get; set; } = false;
2017-12-02 19:47:40 +00:00
2017-12-04 12:38:15 +00:00
public Vector2 Offset { get; set; } = new Vector2(10, 10);
public Vector2 ScaleFactor { get; set; } = new Vector2(0.03f, 4f);
public float HoleSize { get; set; } = 1f;
2017-12-02 19:47:40 +00:00
private int trackLength;
public int TrackLength
{
get
{
if (trackLength == 0)
trackLength = (int)AllNotes().Max((Note arg) => arg.Time);
return trackLength;
}
}
public int MaxNoteNumber {
get {
2017-12-04 12:38:15 +00:00
return SelectedMusicBox.HighestNote.NoteNumber;
}
}
public int MinNoteNumber {
get
{
2017-12-04 12:38:15 +00:00
return SelectedMusicBox.LowestNote.NoteNumber;
}
}
2017-12-04 12:38:15 +00:00
public MusicBox SelectedMusicBox { get; private set; }
private MidiFile midiFile;
2017-12-02 19:47:40 +00:00
public MusicBoxScoreGenerator(string filename, MusicBox inMusicBox)
{
2017-12-04 12:38:15 +00:00
SelectedMusicBox = inMusicBox;
midiFile = MidiFile.Read(filename);
2017-12-02 19:47:40 +00:00
2017-12-03 15:51:22 +00:00
// Set the scale factor based on the strip height of the music box
2017-12-04 12:38:15 +00:00
ScaleFactor = new Vector2(
ScaleFactor.X,
SelectedMusicBox.StripHeightMm / (SelectedMusicBox.NoteCount-1)
2017-12-03 15:51:22 +00:00
);
2017-12-02 19:47:40 +00:00
foreach(Note note in AllNotes()) {
2017-12-04 12:38:15 +00:00
if (!SelectedMusicBox.IsValidNote(note))
Console.Error.WriteLine($"Warning: The note {note} at {note.Time} can't be played by the {SelectedMusicBox}.");
2017-12-02 19:47:40 +00:00
}
}
public void Output(string destinationFilename)
{
2017-12-04 12:38:15 +00:00
Vector2 area = new Vector2(TrackLength, SelectedMusicBox.NoteCount-1).Multiply(ScaleFactor);
Vector2 size = area.Add(Offset.Multiply(2));
2017-12-03 15:51:22 +00:00
SvgWriter svg = new SvgWriter(
destinationFilename,
$"{size.X}mm", $"{size.Y}mm"
) {
UnitSuffix = "mm"
};
2017-12-02 16:44:12 +00:00
// Draw the note lines
for(float i = 0; i < area.Y; i += ScaleFactor.Y) {
2017-12-04 12:38:15 +00:00
Vector2 start = Offset.Add(new Vector2(0, i));
svg.WriteLine(start, start.Add(new Vector2(area.X, 0)), "darkgreen", 0.75f);
2017-12-02 14:38:49 +00:00
}
2017-12-03 15:51:22 +00:00
// Draw a red box around everything
2017-12-04 12:38:15 +00:00
svg.WriteRectangle(Offset, area, "red", 0.75f);
2017-11-30 23:03:55 +00:00
foreach(Note note in AllNotes())
{
2017-12-04 12:38:15 +00:00
if(Debug) {
Console.WriteLine(
"[Note] {0}: {1}{2}/{3}",
note.Time,
note.NoteName,
note.Octave,
note.NoteNumber
);
}
2017-11-30 23:03:55 +00:00
svg.WriteCircle(
new Vector2(
2017-12-04 12:38:15 +00:00
Offset.X + note.Time * ScaleFactor.X,
Offset.Y + ((SelectedMusicBox.NoteCount-1) - SelectedMusicBox.NoteToBoxNumber(note)) * ScaleFactor.Y
2017-11-30 23:03:55 +00:00
),
2017-12-04 12:38:15 +00:00
HoleSize // radius
2017-11-30 23:03:55 +00:00
);
}
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)
2017-11-30 23:03:55 +00:00
yield return note;
}
}
}
}
}