Skip to content

Commit

Permalink
WIP - try to improve note length optimization
Browse files Browse the repository at this point in the history
  • Loading branch information
livvy94 committed Nov 29, 2021
1 parent 735140f commit 0259773
Show file tree
Hide file tree
Showing 4 changed files with 213 additions and 59 deletions.
164 changes: 107 additions & 57 deletions PK Piano/Form1.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
using System.Text;
using NAudio.Wave;
using NAudio.Wave.SampleProviders;
using System.Collections.Generic;

namespace PK_Piano
{
Expand All @@ -30,8 +31,7 @@ public Form1()
byte echoDelay;
byte echoFeedback;
byte echoFilter;

ToneGenerator.PlaybackThing playbackThing = new ToneGenerator.PlaybackThing();
readonly ToneGenerator.PlaybackThing playbackThing = new ToneGenerator.PlaybackThing();

private void SendNote(byte input)
{
Expand Down Expand Up @@ -730,80 +730,130 @@ private void btnMPTconvert_Click(object sender, EventArgs e)

private void btnC8eraser_Click(object sender, EventArgs e)
{
int originalLength = 0x06; //TODO: write something that doesn't rely on this being here and just adds all lengths up

//VALIDATION
string input = Clipboard.GetText();
//string clipboardContents = Clipboard.GetText();
//if (string.IsNullOrWhiteSpace(clipboardContents)) return; //only continue if there's something there
//if (clipboardContents.Contains("Not enough rows to process")) return;

//clipboardContents = clipboardContents.Replace("[", "").Replace("]", ""); //get rid of brackets
//var input = SongPiece.StringToBytes(clipboardContents);
var input = SongPiece.StringToBytes("0C 7F A7 C8 0C A7 C8");
var goodVersion = SongPiece.StringToBytes("18 7F A7 18 A7");
var optimizedBytes = ProcessBytes(input);

RunTest(optimizedBytes, goodVersion);
//Clipboard.SetText(result.ToString());
if (sfxEnabled) sfxEquipped.Play();
}

if (string.IsNullOrWhiteSpace(input)) return; //only continue if there's something there
if (input.Contains("Not enough rows to process")) return;
public static List<byte> ProcessBytes(List<byte> bytesInput)
{
var result = new List<byte>();
var piece = new SongPiece();
bool lastByteWasANote = false;
bool lastByteWasANoteLength = false;
bool lastByteWasAnEffect = false;
int effectSkip = 0;
foreach (var b in bytesInput)
{
if (effectSkip > 0) //for effects with parameters, which shouldn't be processed
{
effectSkip--;
piece.tempNoteCollection.Add(b); //add the effect, byte by byte
continue;
}

//split the contents on spaces to a string array
input = input.Replace("[", "").Replace("]", ""); //get rid of brackets
if (lastByteWasAnEffect)
{
result.AddRange(piece.ParseHex());
piece = new SongPiece(piece.noteLength, piece.noteLengthMultiplier); //keep the old note settings!
lastByteWasAnEffect = false;
}

//Clear out any lingering note length commands in the text itself
var firstCode = Convert.ToInt32(input.Substring(0, 2), 16); //convert the first code in the clipboard to an int
if (firstCode > 0xE0) return; //E0 to FF are all effect commands
if (firstCode < 0x80) //any code less than 80 (C-1) is a note length and should be removed
{
input = input.Replace(firstCode.ToString("X2") + " ", "");
originalLength = firstCode; //if it's not 06, it should be set appropriately so later on the right value gets put at the end of the clipboard result
if (SongPiece.IsNoteLength(b))
{
//Skip redundant note lengths
if (b == piece.noteLength && piece.noteLengthMultiplier == 1)
continue;

if (lastByteWasANote)
{
//Add the contents of tempNoteCollection to the result
result.AddRange(piece.ParseHex());
lastByteWasANote = false;
piece = new SongPiece(); //clear out everything and start from scratch
}

if (lastByteWasANoteLength)
{
piece.noteStyle = b; //It's a note style, like 7F
lastByteWasANoteLength = false;
}
else
{
piece.noteLength = b;
lastByteWasANoteLength = true;
}

continue;
}

if (SongPiece.IsNote(b))
{
lastByteWasANote = true;
lastByteWasANoteLength = false; //just in case
if (b == 0xC8)
{
piece.noteLengthMultiplier++; //keep track of how many C8s there have been
continue;
}
else
{
piece.tempNoteCollection.Add(b); //add the note to the collection
}
}

if (SongPiece.IsEffect(b))
{
effectSkip = SongPiece.GetNumberOfParameters(b);
piece.tempNoteCollection.Add(b);
lastByteWasAnEffect = true;
}
}

//Make a string array with all of the notes in it
var notes = input.Split(' ');
//Add any remaining notes to result
result.AddRange(piece.ParseHex());
return result;
}

if (notes.Length <= 1)
public static void RunTest(List<byte> resultBytes, List<byte> goodVersionBytes)
{
//DIY unit test
string result = "";
foreach (var b in resultBytes)
{
MessageBox.Show("This looks like it's just one note. No changes necessary here!");
return;
result += b.ToString("X2") + " "; //convert the list back into a string
}

//check to see that only the first one is not C8
for (var i = 1; i < notes.Length; i++)
string goodVersion = "";
foreach (var b in goodVersionBytes)
{
if (notes[i] != "C8")
{
MessageBox.Show("Looks like there's more than one note in here...\r\nStripping multiple notes hasn't been implemented yet.\r\n(The note in question is " + notes[i] + ")");
return;
}
goodVersion += b.ToString("X2") + " "; //convert the list back into a string
}

var count = notes.Length;

//returns [new length, appropriate multiplier]
var newLength = EBM_Note_Data.validateNoteLength(originalLength * count);

var message = $"Number of notes: {count}\r\n"
+ "Equivalent note length: ";
result = result.Trim();
goodVersion = goodVersion.Trim();

if (newLength[1] != 1)
message += $"[{newLength[0]:X2}], {getWrittenNumber(newLength[1])} times.";
var message = "";
if (result == goodVersion)
message += "*** PASS ***\r\n";
else
message += $"[{newLength[0]:X2}]";

message += "*** FAIL ***\r\n";
message += "Result:\r\n" + result + "\r\nDesired output:\r\n" + goodVersion;
MessageBox.Show(message);

//set the clipboard to the new length, whatever note is at the start of what was copied, and then the original length so when you paste it in, the rest of the column doesn't go out of whack
var result = new StringBuilder();
result.Append(newLength[0].ToString("X2")); //the length that the new
result.Append(" ");
result.Append(notes[0]); //The note at the top of the clipboard contents
result.Append(" ");

while (newLength[1] > 1) //this should only run if
{
result.Append("C8 "); //put in however many C8s are needed to make this the same size as the original clipboard contents
newLength[1]--;
}
result.Append(originalLength.ToString("X2")); //the 06 so things don't jump around when you paste it in

Clipboard.SetText(result.ToString()); //paste this into EBMusEd for glorious ease of use
if (sfxEnabled) sfxEquipped.Play();
}



//Text blip stuff
//If the sfxEnabled boolean value is set to true, then various parts of the UI will give audio feedback.
//I'm getting kind of tired of it, though, so I'm going to make it toggleable in the future.
Expand Down
3 changes: 1 addition & 2 deletions PK Piano/MPTColumn.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,9 @@

namespace PK_Piano
{
//These classes are a very recent addition. TODO: Move more of the logic to classes like this
class MPTColumn
{
public const string VALID = "Valid!";
public const string VALID = "Valid!"; //TODO: make this validation thing less janky

public static string GetEBMdata(string input)
{
Expand Down
1 change: 1 addition & 0 deletions PK Piano/PK Piano.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,7 @@
<Compile Include="MPTColumn.cs" />
<Compile Include="Program.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="SongPiece.cs" />
<Compile Include="ToneGenerator.cs" />
<EmbeddedResource Include="Form1.resx">
<DependentUpon>Form1.cs</DependentUpon>
Expand Down
104 changes: 104 additions & 0 deletions PK Piano/SongPiece.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
using System;
using System.Collections.Generic;

namespace PK_Piano
{
class SongPiece
{
public byte noteLength;
public byte noteLengthMultiplier;
public List<byte> tempNoteCollection;
public byte noteStyle;

public SongPiece()
{
noteLength = 0xFF;
noteLengthMultiplier = 1;
tempNoteCollection = new List<byte>();
noteStyle = 0xFF;
}

public SongPiece(byte length, byte multiplier)
{
noteLength = length;
noteLengthMultiplier = multiplier;
tempNoteCollection = new List<byte>();
noteStyle = 0xFF;
}

public List<byte> ParseHex()
{
var result = new List<byte>();
result.Add((byte)(noteLength * noteLengthMultiplier));

if (noteStyle != 0xFF)
result.Add(noteStyle);

result.AddRange(tempNoteCollection);
return result;
}

public static bool IsNoteLength(byte b) => b <= 0x7F;
public static bool IsNote(byte b) => b >= 0x80 && b <= 0xDF;
public static bool IsEffect(byte b) => b >= 0xE0;

public static int GetNumberOfParameters(byte b)
{
switch (b)
{
case 0xE4:
case 0xEC:
case 0xF3:
case 0xF6:
case 0xFC:
case 0xFD:
case 0xFE:
case 0xFF:
return 0; //these commands have no parameters
case 0xE0:
case 0xE1:
case 0xE5:
case 0xE7:
case 0xE9:
case 0xEA:
case 0xED:
case 0xF0:
case 0xF4:
case 0xFA:
return 1;
case 0xE2:
case 0xE6:
case 0xE8:
case 0xEE:
case 0xFB:
return 2;
case 0xE3:
case 0xEB:
case 0xF1:
case 0xF2:
case 0xF5:
case 0xF7:
case 0xF8:
case 0xF9:
return 3;
case 0xEF:
throw new Exception("The [EF] command is unimplemented.\r\nPlease use the *subroutine,count syntax instead.");
}
return 0;
}

//TODO: Switch statement for returning an int of how many parameters an effect has in it!

public static List<byte> StringToBytes(string input)
{
var bytes = input.Split(' ');
var bytesInput = new List<byte>();
foreach (var b in bytes)
{
bytesInput.Add(Convert.ToByte(b, 16));
}

return bytesInput;
}
}
}

0 comments on commit 0259773

Please sign in to comment.