Skip to content

Commit

Permalink
refactor: #1 keeping codes clean.
Browse files Browse the repository at this point in the history
  • Loading branch information
hiroxpepe committed Oct 15, 2022
1 parent 6def55e commit 7268979
Show file tree
Hide file tree
Showing 6 changed files with 61 additions and 24 deletions.
2 changes: 1 addition & 1 deletion Meowziq.Midi/Midi/Manager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@

namespace Meowziq.Midi {
/// <summary>
/// midi class using Sanford.Multimedia.Midi
/// MIDI class using Sanford.Multimedia.Midi
/// </summary>
/// <author>h.adachi (STUDIO MeowToon)</author>
public class Manager {
Expand Down
42 changes: 21 additions & 21 deletions Meowziq.View/FormMain.cs
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@ async void buttonLoad_Click(object sender, EventArgs e) {
}

/// <summary>
/// converts the song data to smf.
/// converts the song data to SMF.
/// </summary>
async void buttonConvert_Click(object sender, EventArgs e) {
try {
Expand All @@ -142,22 +142,22 @@ async void buttonConvert_Click(object sender, EventArgs e) {
}

/// <summary>
/// throws midi data to the device.
/// throws MIDI data to the device.
/// </summary>
/// <remarks>
/// + depends on the conductor.midi and is only called every 30 ticks. <br/>
/// + ignores messages in the conductor.midi. midi.OutDevice.Send(e.Message); <br/>
/// + variable named tick defines to be always an absolute value. <br/>
/// </remarks>
/// <todo>
/// is it possible to independently implement the timing of message transmission to the midi device?
/// is it possible to independently implement the timing of message transmission to the MIDI device?
/// </todo>
void sequencer_ChannelMessagePlayed(object sender, ChannelMessageEventArgs e) {
if (Sound.Stopping) { return; }
if (Visible) {
State.Tick = _sequencer.Position - 1; // NOTE: tick position comes with 1, 31, so subtract 1 in advance.
if (State.SameTick) { return; };
// midi message processing.
// MIDI message processing.
Midi.Message.ApplyTick(tick: State.Repeat.Tick, load: loadSong); // switches every 2 beats. MEMO: considers syncopation.
var list = Midi.Message.GetBy(tick: State.Repeat.Tick); // gets the list of midi messages.
if (list is not null) {
Expand Down Expand Up @@ -188,7 +188,7 @@ void sequencer_ChannelMessagePlayed(object sender, ChannelMessageEventArgs e) {
/// loads a song data fully while stopped.
/// </summary>
/// <remarks>
/// also called from smf output.
/// also called from SMF output.
/// </remarks>
async Task<string> buildSong(bool smf = false) {
var name = "------------";
Expand Down Expand Up @@ -225,7 +225,7 @@ await Task.Run(action: () => {
catch (Exception ex) {
if (!_ex_message.Equals(ex.Message)) { // if the error message is different,
_ = Task.Factory.StartNew(action: () => { // displays an error dialog.
_result = MessageBox.Show(ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Stop);
_result = MessageBox.Show(text: ex.Message, caption: "Error", buttons: MessageBoxButtons.OK, icon: MessageBoxIcon.Stop);
if (_result is DialogResult.OK) { // when closed with ok.
_ex_message = string.Empty; // initializes the flag and show the dialog again if necessary.
}
Expand All @@ -250,12 +250,12 @@ void buildResourse(int tick, bool current = true, bool smf = false) {
PlayerLoader<ChannelMessage>.PhraseList = PhraseLoader.Build(target: current ? Cache.Current.PhraseStream : Cache.Valid.PhraseStream);
PlayerLoader<ChannelMessage>.Build(target: current ? Cache.Current.PlayerStream : Cache.Valid.PlayerStream).ForEach(x => {
x.Song = song; // sets song data.
x.Build(tick: tick, smf: smf); // builds midi data.
x.Build(tick: tick, smf: smf); // builds MIDI data.
});
}

/// <summary>
/// converts the song to smf and output as a file.
/// converts the song to SMF and output as a file.
/// </summary>
/// <todo>
/// stop playing the song.
Expand All @@ -267,15 +267,15 @@ async Task<bool> convertSong() {
/// </summary>
var message = "PLEASE WAIT";
IObservable<long> timer = Observable.Timer(dueTime: TimeSpan.FromSeconds(1), period: TimeSpan.FromSeconds(1));
IDisposable disposer = timer.Subscribe(x => {
IDisposable disposer = timer.Subscribe(onNext: x => {
Log.Info($"converting the song.. ({x})");
Invoke(method: (MethodInvoker) (() => {
var dot = (x % 2) == 0 ? "*" : "-";
_textbox_song_name.Text = $"{message} {dot}";
}));
});
/// <summary>
/// midi data generation.
/// MIDI data generation.
/// </summary>
Midi.Message.Clear();
var song_name = await buildSong(smf: true);
Expand All @@ -288,29 +288,29 @@ async Task<bool> convertSong() {
conductor_track.Insert(position: 0, new MetaMessage(MetaType.Tempo, Value.Converter.ToByteTempo(State.Tempo)));
conductor_track.Insert(position: 0, new MetaMessage(MetaType.TrackName, Value.Converter.ToByteArray(State.Name)));
conductor_track.Insert(position: 0, new MetaMessage(MetaType.Copyright, Value.Converter.ToByteArray(State.Copyright)));
State.TrackList.ForEach(x => {
State.TrackList.ForEach(action: x => {
var ch_track = Multi.Get(index: x.MidiCh);
ch_track.Insert(position: 0, new MetaMessage(MetaType.TrackName, Value.Converter.ToByteArray(x.Name)));
ch_track.Insert(position: 0, new MetaMessage(MetaType.ProgramName, Value.Converter.ToByteArray(x.Instrument))); // FIXME: not reflected?
});
/// <summary>
/// applies midi data.
/// applies MIDI data.
/// </summary>
for (var index = 0; Midi.Message.Has(tick: index * 30); index++) { // loops every 30 ticks.
var tick = index * 30; // manually generates 30 ticks.
var list = Midi.Message.GetBy(tick: tick); // gets list of messages.
if (list is not null) {
list.ForEach(x => Multi.Get(index: x.MidiChannel).Insert(position: tick, message: x));
list.ForEach(action: x => Multi.Get(index: x.MidiChannel).Insert(position: tick, message: x));
}
}
/// <summary>
/// smf file export.
/// SMF file export.
/// </summary>
_sequence.Load("./data/conductor.mid"); // TODO: need this?
_sequence.Clear();
_sequence.Format = 1;
_sequence.Add(item: conductor_track); // adds conductor track.
Multi.List.Where(x => x.Length > 1).ToList().ForEach(x => _sequence.Add(item: x)); // adds channel tracks.
Multi.List.Where(predicate: x => x.Length > 1).ToList().ForEach(action: x => _sequence.Add(item: x)); // adds channel tracks.
_sequence.Save($"./data/{song_dir}/{song_name}.mid");
Invoke(method: (MethodInvoker) (() => _textbox_song_name.Text = song_name));// restores the song name.
disposer.Dispose(); // discard timer.
Expand All @@ -327,7 +327,7 @@ async Task<bool> startSound() {
Midi.Message.Clear();
_textbox_song_name.Text = await buildSong();
Facade.CreateConductor(sequence: _sequence);
_sequence.Load("./data/conductor.mid"); // FIXME: to const value.
_sequence.Load(CONDUCTOR_MIDI); // FIXME: to const value.
_sequencer.Position = 0;
_sequencer.Start();
_label_play.ForeColor = Lime;
Expand All @@ -345,7 +345,7 @@ async Task<bool> stopSound() {
return await Task.Run(function: () => {
Sound.Stopping = true;
Enumerable.Range(start: MIDI_TRACK_BASE, count: MIDI_TRACK_COUNT).ToList().ForEach(
x => _midi.OutDevice.Send(new ChannelMessage(ChannelCommand.Controller, x, 120))
action: x => _midi.OutDevice.Send(new ChannelMessage(ChannelCommand.Controller, x, 120))
);
Sound.Stopping = false;
Sound.Playing = false;
Expand Down Expand Up @@ -408,7 +408,7 @@ MethodInvoker updateDisplay(State.Item16beat item) {
MethodInvoker resetDisplay() {
return () => {
Enumerable.Range(start: 0, count: 88).ToList().ForEach(
x => _piano_control.Send(message: new ChannelMessage(command: ChannelCommand.NoteOff, midiChannel: 1, data1: x, data2: 0))
action: x => _piano_control.Send(message: new ChannelMessage(command: ChannelCommand.NoteOff, midiChannel: 1, data1: x, data2: 0))
);
_label_play.ForeColor = DimGray;
_label_modulation.ForeColor = DimGray;
Expand All @@ -434,7 +434,7 @@ static class Facade {
// public static Methods [verb]

/// <summary>
/// creates and outputs an smf file for tempo control.
/// creates and outputs an SMF file for tempo control.
/// </summary>
public static void CreateConductor(Sequence sequence) {
MetaMessage tempo = new(type: MetaType.Tempo, data: Value.Converter.ToByteTempo(tempo: State.Tempo));
Expand All @@ -445,10 +445,10 @@ public static void CreateConductor(Sequence sequence) {
track.Insert(position: tick, message: new ChannelMessage(command: ChannelCommand.NoteOn, midiChannel: 0, data1: 64, data2: 0));
track.Insert(position: tick + 30, message: new ChannelMessage(command: ChannelCommand.NoteOff, midiChannel: 0, data1: 64, data2: 0));
}
sequence.Load("./data/conductor.mid"); // TODO: need this? // FIXME: to const value.
sequence.Load(CONDUCTOR_MIDI); // FIXME: still need for tempo.
sequence.Clear();
sequence.Add(item: track);
sequence.Save($"./data/conductor.mid"); // smf file export for tempo control. // FIXME: to const value.
sequence.Save(CONDUCTOR_MIDI); // SMF file export for tempo control.
}
}

Expand Down
2 changes: 1 addition & 1 deletion Meowziq/Core/Note.cs
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ public int Gate {
}

/// <summary>
/// midi note strength.
/// MIDI note strength.
/// </summary>
/// <note>
/// + not provide modify operations.
Expand Down
2 changes: 2 additions & 0 deletions Meowziq/Env.cs
Original file line number Diff line number Diff line change
Expand Up @@ -34,5 +34,7 @@ public static class Env {
public static readonly int NOTE_RESOLUTION = 480;

public static readonly string COUNT_PATTERN = "count";

public static readonly string CONDUCTOR_MIDI = "./data/conductor.mid";
}
}
35 changes: 35 additions & 0 deletions Meowziq/IO/IOUtils.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
/*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/

using System.IO;

namespace Meowziq.IO {
/// <summary>
/// IO utils functions.
/// <author>h.adachi (STUDIO MeowToon)</author>
public static class IOUtils {
/// <summary>
/// creates a directory if necessary.
/// </summary>
public static DirectoryInfo MakeDirectoryIfNecessary(string target) {
string directory = Path.GetDirectoryName(target);
bool exists = Directory.Exists(directory);
if (!exists) {
return Directory.CreateDirectory(directory);
}
return null;
}
}
}
2 changes: 1 addition & 1 deletion Meowziq/Value/Validater.cs
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ internal static string Filter(string target) {
/// </todo>
public static class Converter {
/// <summary>
/// converts numeric BPM to tempo information for smf.
/// converts numeric BPM to tempo information for SMF.
/// </summary>
/// <summary_jp>
/// BPM = 120 (1分あたり四分音符が120個) の場合、<br/>
Expand Down

0 comments on commit 7268979

Please sign in to comment.