public static int RunGenerateAndReturnExitCode(GenerateOptions opts) { if (!opts.PatchType.Equals("single")) { Console.WriteLine($"Sorry, I don't know how to generate {opts.PatchType} patches."); return(-1); } Console.WriteLine("OK, you want to generate a single patch."); Console.WriteLine($"And you want to call it '{opts.PatchName}'."); SinglePatch singlePatch = new SinglePatch(); // Override the patch defaults singlePatch.Name = opts.PatchName; singlePatch.Volume = 100; singlePatch.Effect = 1; byte[] data = GenerateSystemExclusiveMessage(singlePatch, PatchUtil.GetPatchNumber(opts.PatchNumber)); Console.WriteLine("Generated single patch as a SysEx message:"); Console.WriteLine(Util.HexDump(data)); // Write the data to the output file File.WriteAllBytes(opts.OutputFileName, data); return(0); }
public static int RunExtractAndReturnExitCode(ExtractOptions opts) { if (!opts.PatchType.Equals("single")) { Console.WriteLine($"Sorry, I don't know how to extract {opts.PatchType} patches."); return(-1); } string inputFileName = opts.InputFileName; byte[] fileData = File.ReadAllBytes(inputFileName); Bank bank = new Bank(fileData); int sourcePatchNumber = PatchUtil.GetPatchNumber(opts.SourcePatchNumber); SinglePatch patch = bank.Singles[sourcePatchNumber]; int destinationPatchNumber = PatchUtil.GetPatchNumber(opts.DestinationPatchNumber); byte[] patchData = GenerateSystemExclusiveMessage(patch, destinationPatchNumber); // Write the data to the output file File.WriteAllBytes(opts.OutputFileName, patchData); return(0); }
private void LoadFile() { if (_fileName != null) { var data = System.IO.File.ReadAllBytes(_fileName); _singlePatch = new SinglePatch(data); _singlePatchView.Patch = _singlePatch; } }
public static int RunDumpAndReturnExitCode(DumpOptions opts) { string fileName = opts.FileName; byte[] fileData = File.ReadAllBytes(fileName); Console.WriteLine($"SysEx file: '{fileName}' ({fileData.Length} bytes)"); List <byte[]> messages = Util.SplitBytesByDelimiter(fileData, 0xf7); Console.WriteLine($"Got {messages.Count} messages"); foreach (byte[] message in messages) { byte[] rawData = ExtractPatchData(message); byte[] data = Util.ConvertFromTwoNybbleFormat(rawData); SystemExclusiveHeader header = new SystemExclusiveHeader(message); Console.WriteLine(header); // TODO: Check the SysEx file header for validity Console.WriteLine(String.Format("Function = {0}", ((SystemExclusiveFunction)header.Function)).ToString().ToUpper()); if (header.Substatus1 == 0x00) { Console.WriteLine("SINGLE"); } else if (header.Substatus1 == 0x01) { Console.WriteLine("MULTI"); } Console.WriteLine(String.Format("Program = {0}", header.Substatus2)); int programNumber = header.Substatus2; string programType = "INTERNAL"; if (programNumber >= 48) { programType = "EXTERNAL"; programNumber -= 48; } string programName = GetProgramName(programNumber); Console.WriteLine(String.Format("{0} {1}", programType, programName)); SinglePatch s = new SinglePatch(data); System.Console.WriteLine(s.ToString()); } return(0); }
public static int RunExtractAndReturnExitCode(ExtractOptions opts) { string fileName = opts.FileName; byte[] fileData = File.ReadAllBytes(fileName); Console.WriteLine($"SysEx file: '{fileName}' ({fileData.Length} bytes)"); List <byte[]> messages = Util.SplitBytesByDelimiter(fileData, 0xf7); Console.WriteLine($"Got {messages.Count} messages"); int programNumber = GetProgramNumber(opts.PatchNumber); foreach (byte[] message in messages) { SystemExclusiveHeader header = new SystemExclusiveHeader(message); if (header.Substatus2 != programNumber) { continue; } byte[] rawData = ExtractPatchData(message); byte[] data = Util.ConvertFromTwoNybbleFormat(rawData); SinglePatch s = new SinglePatch(data); int channel = opts.Channel - 1; // adjust channel 1...16 to range 0...15 byte[] newHeader = new byte[] { 0xF0, 0x40, (byte)(channel - 1), 0x20, 0x00, 0x02, 0x00, (byte)programNumber }; List <byte> newData = new List <byte>(); newData.AddRange(newHeader); newData.AddRange(Util.ConvertToTwoNybbleFormat(s.ToData())); newData.Add(0xf7); var folder = Environment.SpecialFolder.Desktop; var newFileName = Path.Combine(new string[] { Environment.GetFolderPath(folder), $"{s.Name.Trim()}.syx" }); Console.WriteLine($"Writing SysEx data to '{newFileName}'..."); File.WriteAllBytes(newFileName, newData.ToArray()); } return(0); }
public SinglePatch Generate() { SinglePatch single = new SinglePatch(); single.SingleCommon.Name = Descriptor.Name; single.SingleCommon.Volume.Value = 115; single.SingleCommon.SourceCount = Descriptor.Sources.Count; single.SingleCommon.IsPortamentoEnabled = false; single.SingleCommon.PortamentoSpeed.Value = 0; single.Sources = new Source[single.SingleCommon.SourceCount]; for (int i = 0; i < single.SingleCommon.SourceCount; i++) { single.Sources[i] = GenerateSource(Descriptor.Sources[i]); } return(single); }
// Create an init patch. This is a single patch with basic settings. public static int RunInitAndReturnExitCode(InitOptions opts) { Console.WriteLine("Init"); var patch = new SinglePatch(); patch.SingleCommon.Name = "DS Init"; patch.SingleCommon.Volume.Value = 115; patch.SingleCommon.SourceCount = 2; patch.Sources = new Source[patch.SingleCommon.SourceCount]; for (int i = 0; i < patch.SingleCommon.SourceCount; i++) { patch.Sources[i] = new Source(); } Console.WriteLine(patch.ToString()); return(0); }
private static byte[] GenerateSystemExclusiveMessage(SinglePatch patch, int patchNumber, int channel = 0) { List <byte> data = new List <byte>(); SystemExclusiveHeader header = new SystemExclusiveHeader(); header.ManufacturerID = 0x40; // Kawai header.Channel = (byte)channel; header.Function = (byte)SystemExclusiveFunction.OnePatchDataDump; header.Group = 0x00; // synth group header.MachineID = 0x04; // K4/K4r header.Substatus1 = 0x00; // INT header.Substatus2 = (byte)patchNumber; data.Add(SystemExclusiveHeader.Initiator); data.AddRange(header.ToData()); data.AddRange(patch.ToData()); data.Add(SystemExclusiveHeader.Terminator); return(data.ToArray()); }
public static int RunCreateAndReturnExitCode(CreateOptions opts) { //byte[] data = ExtractPatchData(message); //Single s = new Single(data); SinglePatch s = new SinglePatch(); s.Name = "FRANKENP"; byte[] newHarmonics = LeiterEngine.GetHarmonicLevels("saw", Source.HarmonicCount); for (int i = 0; i < Source.HarmonicCount; i++) { s.Source1.Harmonics[i].Level = newHarmonics[i]; s.Source2.Harmonics[i].Level = newHarmonics[i]; } s.Source1.Amplifier.EnvelopeSegments = Amplifier.Envelopes["regular"].Segments; s.Source2.Amplifier.EnvelopeSegments = Amplifier.Envelopes["silent"].Segments; int channel = 1; byte[] newHeader = new byte[] { 0xF0, 0x40, (byte)(channel - 1), 0x20, 0x00, 0x02, 0x00, 0x2F }; List <byte> newData = new List <byte>(); newData.AddRange(newHeader); newData.AddRange(Util.ConvertToTwoNybbleFormat(s.ToData())); newData.Add(0xf7); Console.WriteLine("Creating new patch, new SysEx data:\n{0}", Util.HexDump(newData.ToArray())); var folder = Environment.SpecialFolder.Desktop; var newFileName = Path.Combine(new string[] { Environment.GetFolderPath(folder), "Frankenpatch.syx" }); Console.WriteLine($"Writing SysEx data to '{newFileName}'..."); File.WriteAllBytes(newFileName, newData.ToArray()); return(0); }
private static string MakeTextList(byte[] data, string title) { //Console.WriteLine($"MakeTextList: data length = {data.Length} bytes"); StringBuilder sb = new StringBuilder(); sb.Append("SINGLE patches:\n"); int offset = 0; for (int i = 0; i < SinglePatchCount; i++) { byte[] singleData = new byte[SinglePatch.DataSize]; Buffer.BlockCopy(data, offset, singleData, 0, SinglePatch.DataSize); //Console.WriteLine($"Constructing single patch from {singleData.Length} bytes of data starting at {offset}"); SinglePatch single = new SinglePatch(singleData); string name = PatchUtil.GetPatchName(i); sb.Append($"S{name} {single.Name}\n"); if ((i + 1) % 16 == 0) { sb.Append("\n"); } offset += SinglePatch.DataSize; } sb.Append("\n"); sb.Append("MULTI patches:\n"); for (int i = 0; i < MultiPatchCount; i++) { byte[] multiData = new byte[MultiPatch.DataSize]; Buffer.BlockCopy(data, offset, multiData, 0, MultiPatch.DataSize); //Console.WriteLine($"Constructing multi patch from {multiData.Length} bytes of data starting at {offset}"); MultiPatch multi = new MultiPatch(multiData); string name = PatchUtil.GetPatchName(i); sb.Append($"M{name} {multi.Name}\n"); if ((i + 1) % 16 == 0) { sb.Append("\n"); } offset += MultiPatch.DataSize; } /* * sb.Append("\n"); * sb.Append("DRUM:\n"); * byte[] drumData = new byte[DrumPatch.DataSize]; * Buffer.BlockCopy(data, offset, drumData, 0, DrumPatch.DataSize); * Console.WriteLine($"Constructing drum patch from {drumData.Length} bytes of data starting at {offset}"); * DrumPatch drumPatch = new DrumPatch(drumData); */ offset += DrumPatch.DataSize; sb.Append("\n"); sb.Append("EFFECT SETTINGS:\n"); for (int i = 0; i < 32; i++) { byte[] effectData = new byte[EffectPatch.DataSize]; Buffer.BlockCopy(data, offset, effectData, 0, EffectPatch.DataSize); //Console.WriteLine($"Constructing effect patch from {effectData.Length} bytes of data starting at {offset}"); EffectPatch effectPatch = new EffectPatch(effectData); sb.Append($"E-{i+1,2} {effectPatch}"); offset += EffectPatch.DataSize; } return(sb.ToString()); }
public static int RunInitAndReturnExitCode(InitOptions opts) { List <SinglePatch> singlePatches = new List <SinglePatch>(); for (int i = 0; i < SinglePatchCount; i++) { SinglePatch single = new SinglePatch(); singlePatches.Add(single); } List <MultiPatch> multiPatches = new List <MultiPatch>(); for (int i = 0; i < MultiPatchCount; i++) { MultiPatch multi = new MultiPatch(); multiPatches.Add(multi); } // Create a System Exclusive header for an "All Patch Data Dump" SystemExclusiveHeader header = new SystemExclusiveHeader(); header.ManufacturerID = 0x40; // Kawai header.Channel = 0; // MIDI channel 1 header.Function = (byte)SystemExclusiveFunction.AllPatchDataDump; header.Group = 0; // synthesizer group header.MachineID = 0x04; // K4/K4r ID header.Substatus1 = 0; // INT header.Substatus2 = 0; // always zero List <byte> data = new List <byte>(); data.Add(SystemExclusiveHeader.Initiator); data.AddRange(header.ToData()); // Single patches: 64 * 131 = 8384 bytes of data foreach (SinglePatch s in singlePatches) { data.AddRange(s.ToData()); } // Multi patches: 64 * 77 = 4928 bytes of data // The K4 MIDI spec has an error in the "All Patch Data" description; // multi patches are listed as 87, not 77 bytes foreach (MultiPatch m in multiPatches) { data.AddRange(m.ToData()); } // Drums: 682 bytes of data DrumPatch drums = new DrumPatch(); data.AddRange(drums.ToData()); List <EffectPatch> effectPatches = new List <EffectPatch>(); for (int i = 0; i < EffectPatchCount; i++) { EffectPatch effect = new EffectPatch(); effectPatches.Add(effect); } // Effect patches: 32 * 35 = 1120 bytes of data foreach (EffectPatch e in effectPatches) { data.AddRange(e.ToData()); } data.Add(SystemExclusiveHeader.Terminator); // SysEx initiator: 1 // SysEx header: 7 // Single patches: 8384 // Multi patches: 4928 // Drum settings: 682 // Effect patches: 1120 // SysEx terminator: 1 // Total bytes: 15123 // Write the data to the output file File.WriteAllBytes(opts.OutputFileName, data.ToArray()); return(0); }
private static string MakeHtmlList(byte[] data, string title) { string GetNoteName(int noteNumber) { string[] notes = new string[] { "C", "C#", "D", "Eb", "E", "F", "F#", "G", "G#", "A", "Bb", "B" }; int octave = noteNumber / 12 + 1; string name = notes[noteNumber % 12]; return(name + octave); } StringBuilder sb = new StringBuilder(); sb.Append(String.Format("<h1>{0}</h1>\n", title)); SinglePatch[][] singleBanks = new SinglePatch[BankCount][]; //BankCount, PatchesPerBank]; int offset = 0; int patchSize = SinglePatch.DataSize; for (int bankNumber = 0; bankNumber < BankCount; bankNumber++) { SinglePatch[] patches = new SinglePatch[PatchesPerBank]; for (int patchNumber = 0; patchNumber < PatchesPerBank; patchNumber++) { byte[] singleData = new byte[patchSize]; Buffer.BlockCopy(data, offset, singleData, 0, patchSize); SinglePatch single = new SinglePatch(singleData); patches[patchNumber] = single; offset += patchSize; } singleBanks[bankNumber] = patches; } // Now we should have all the single patches collected in four lists of 16 each sb.Append("<table>\n"); sb.Append("<tr>\n <th>SINGLE</th>\n"); for (int bankNumber = 0; bankNumber < BankCount; bankNumber++) { char bankLetter = "ABCD"[bankNumber]; sb.Append(String.Format(" <th>{0}</th>\n", bankLetter)); } sb.Append("</tr>\n"); for (int patchNumber = 0; patchNumber < PatchesPerBank; patchNumber++) { sb.Append("<tr>\n"); sb.Append(String.Format(" <td>{0,2}</td>\n", patchNumber + 1)); for (int bankNumber = 0; bankNumber < BankCount; bankNumber++) { SinglePatch[] patches = singleBanks[bankNumber]; string patchId = PatchUtil.GetPatchName(bankNumber * patchNumber); SinglePatch single = patches[patchNumber]; sb.Append(String.Format($" <td>{single.Name:10}</td>\n")); } sb.Append("</tr>\n"); } sb.Append("</table>\n"); // // Multi patches // patchSize = MultiPatch.DataSize; MultiPatch[][] multiBanks = new MultiPatch[BankCount][]; for (int bankNumber = 0; bankNumber < BankCount; bankNumber++) { MultiPatch[] patches = new MultiPatch[PatchesPerBank]; for (int patchNumber = 0; patchNumber < PatchesPerBank; patchNumber++) { byte[] multiData = new byte[patchSize]; Buffer.BlockCopy(data, offset, multiData, 0, patchSize); MultiPatch multi = new MultiPatch(multiData); patches[patchNumber] = multi; offset += patchSize; } multiBanks[bankNumber] = patches; } sb.Append("<table>\n"); sb.Append("<tr>\n <th>MULTI</th>\n"); for (int bankNumber = 0; bankNumber < BankCount; bankNumber++) { char bankLetter = "ABCD"[bankNumber]; sb.Append(String.Format(" <th>{0}</th>\n", bankLetter)); } sb.Append("</tr>\n"); for (int patchNumber = 0; patchNumber < PatchesPerBank; patchNumber++) { sb.Append("<tr>\n"); sb.Append(String.Format(" <td>{0,2}</td>\n", patchNumber + 1)); for (int bankNumber = 0; bankNumber < BankCount; bankNumber++) { MultiPatch[] patches = multiBanks[bankNumber]; string patchId = PatchUtil.GetPatchName(bankNumber * patchNumber); MultiPatch single = patches[patchNumber]; sb.Append(String.Format($" <td>{single.Name:10}</td>\n")); } sb.Append("</tr>\n"); } sb.Append("</table>\n"); patchSize = DrumPatch.DataSize; // TODO: List drum // Crash when setting tune of drum note (value out of range) /* * sb.Append("<table>\n"); * sb.Append("<caption>DRUM</caption>\n"); * sb.Append("<tr><th>Note</th><th>Parameters</th></tr>\n"); * * patchSize = DrumPatch.DataSize; * byte[] drumData = new byte[patchSize]; * Buffer.BlockCopy(data, offset, drumData, 0, patchSize); * var drum = new DrumPatch(drumData); * for (int i = 0; i < 128; i++) * { * var note = drum.Notes[i]; * sb.Append($"<tr><td>E-{GetNoteName(i)}</td><td>{note}</td></tr>\n"); * } * * sb.Append("</table>\n"); */ offset += patchSize; sb.Append("<table>\n"); sb.Append("<caption>EFFECT</caption>\n"); sb.Append("<tr><th>#</th><th>Type and parameters</th></tr>\n"); patchSize = EffectPatch.DataSize; for (int i = 0; i < 32; i++) { byte[] effectData = new byte[patchSize]; Buffer.BlockCopy(data, offset, effectData, 0, patchSize); //Console.WriteLine($"Constructing effect patch from {effectData.Length} bytes of data starting at {offset}"); EffectPatch effectPatch = new EffectPatch(effectData); sb.Append($"<tr><td>E-{i+1,2}</td><td>{effectPatch}</td></tr>\n"); offset += patchSize; } sb.Append("</table>\n"); return(sb.ToString()); }
public int ListPatches() { // SysEx header at this point should be "F0 40 00 21 00 0A 00 00" followed by the tone map var offset = 8; // skip to the tone map //Console.Error.WriteLine($"offset = {offset}"); // For a block data dump, need to parse the tone map byte[] buffer; (buffer, offset) = Util.GetNextBytes(this.data, offset, PatchMap.Size); // now the offset has been updated to past the tone map //Console.Error.WriteLine($"offset = {offset}"); var patchMap = new PatchMap(buffer); List <int> patchNumbers = new List <int>(); //Console.WriteLine("Patches included:"); var patchCount = 0; for (var i = 0; i < PatchMap.PatchCount; i++) { if (patchMap[i]) { patchCount += 1; //Console.Write(i + 1); //Console.Write(" "); patchNumbers.Add(i); } } //Console.WriteLine($"\nTotal = {patchCount} patches"); // Whatever the first patch is, it must be at least this many bytes (always has at least two sources) var minimumPatchSize = SingleCommonSettings.DataSize + 2 * KSynthLib.K5000.Source.DataSize; //Console.Error.WriteLine($"minimum patch size = {minimumPatchSize}"); var totalPatchSize = 0; // the total size of all the single patches var allPatchInfos = new List <PatchInfo>(); var singlePatches = new List <SinglePatch>(); foreach (var patchNumber in patchNumbers) { var startOffset = offset; // save the current offset because we need to copy more bytes later var sizeToRead = Math.Max(minimumPatchSize, this.data.Length - offset); //Console.WriteLine($"About to read {sizeToRead} bytes starting from offset {offset:X4}h"); // We don't know yet how many bytes the patch is, but it is at least the minimum size (buffer, offset) = Util.GetNextBytes(this.data, offset, sizeToRead); // the offset has now been updated past the read size, so need to adjust it back later //Console.Error.WriteLine(Util.HexDump(buffer)); //Console.Error.WriteLine($"checksum = {buffer[0]:X2}H"); var patch = new SinglePatch(buffer); // Find out how many PCM and ADD sources var pcmCount = 0; var addCount = 0; foreach (var source in patch.Sources) { if (source.IsAdditive) { addCount += 1; } else { pcmCount += 1; } } // Figure out the total size of the single patch based on the counts var patchSize = 1 + SingleCommonSettings.DataSize // includes the checksum + patch.Sources.Length * KSynthLib.K5000.Source.DataSize // all sources have this part + addCount * AdditiveKit.DataSize; //Console.WriteLine($"{pcmCount}PCM {addCount}ADD size={patchSize} bytes"); offset = startOffset; // back up to the start of the patch data // Read the whole patch now that we know its size //Console.WriteLine($"About to read {patchSize} bytes starting from offset {offset:X4}h"); (buffer, offset) = Util.GetNextBytes(this.data, offset, patchSize); totalPatchSize += patchSize; singlePatches.Add(patch); var patchInfo = new PatchInfo { Bank = this.Header.Bank, PatchNumber = patchNumber + 1, PatchName = patch.SingleCommon.Name, PCMSourceCount = pcmCount, AdditiveSourceCount = addCount, }; Console.WriteLine($"{patchInfo.Bank}{patchInfo.PatchNumber:D3} | {patchInfo.PatchName,8} | {patchInfo.PCMSourceCount}PCM {patchInfo.AdditiveSourceCount}ADD"); allPatchInfos.Add(patchInfo); } foreach (var patchInfo in allPatchInfos) { Console.WriteLine($"{patchInfo.Bank}{patchInfo.PatchNumber:D3} | {patchInfo.PatchName,8} | {patchInfo.PCMSourceCount}PCM {patchInfo.AdditiveSourceCount}ADD"); } return(0); }
public static int RunCreateAndReturnExitCode(CreateOptions opts) { var header = new SystemExclusiveHeader(0x00); header.Function = (byte)SystemExclusiveFunction.OneBlockDump; header.Group = 0x00; header.MachineID = 0x0A; header.Substatus1 = 0x00; // single // Get the right bank. Since it is a required parameter, I suppose we can trust that it exists. string bankName = opts.BankName.ToLower(); char ch = bankName[0]; switch (ch) { case 'a': header.Substatus2 = 0x00; break; case 'd': header.Substatus2 = 0x02; break; case 'e': header.Substatus2 = 0x03; break; case 'f': header.Substatus2 = 0x04; break; default: Console.WriteLine(string.Format("Unknown bank: '{0}'", opts.BankName)); return(-1); } var allData = new List <byte>(); // SysEx initiator and basic header data allData.Add(SystemExclusiveHeader.Initiator); allData.AddRange(header.ToData()); // Additional header data as required var patchNumber = opts.PatchNumber - 1; if (patchNumber < 0 || patchNumber > 127) { Console.WriteLine("Patch number must be 1...128"); return(-1); } allData.Add((byte)patchNumber); SinglePatchGenerator generator; SinglePatchDescriptor descriptor; if (opts.PatchType.Equals("single")) { if (!string.IsNullOrEmpty(opts.Descriptor)) // we have a JSON descriptor file, parse it { var jsonText = File.ReadAllText(opts.Descriptor); descriptor = JsonConvert.DeserializeObject <SinglePatchDescriptor>(jsonText); generator = new SinglePatchGenerator(descriptor); } else { descriptor = new SinglePatchDescriptor(); generator = new SinglePatchGenerator(descriptor); } SinglePatch single = generator.Generate(); byte[] singleData = single.ToData(); Console.Error.WriteLine(string.Format("Generated single data size: {0} bytes", singleData.Length)); Console.Error.WriteLine(single.ToString()); allData.AddRange(singleData); allData.Add(SystemExclusiveHeader.Terminator); File.WriteAllBytes(opts.OutputFileName, allData.ToArray()); } else if (opts.PatchType.Equals("multi")) { Console.WriteLine("Don't know how to make a multi patch yet"); return(1); } return(0); }
private static void ProcessMessage(byte[] message) { Console.WriteLine($"Message length = {message.Length} bytes"); var header = new SystemExclusiveHeader(message); //Console.WriteLine("{0}", header); var functionNames = new Dictionary <SystemExclusiveFunction, string>() { { SystemExclusiveFunction.OneBlockDumpRequest, "One Block Dump Request" }, { SystemExclusiveFunction.AllBlockDumpRequest, "All Block Dump Request" }, { SystemExclusiveFunction.ParameterSend, "Parameter Send" }, { SystemExclusiveFunction.TrackControl, "Track Control" }, { SystemExclusiveFunction.OneBlockDump, "One Block Dump" }, { SystemExclusiveFunction.AllBlockDump, "All Block Dump" }, { SystemExclusiveFunction.ModeChange, "Mode Change" }, { SystemExclusiveFunction.Remote, "Remote" }, { SystemExclusiveFunction.WriteComplete, "Write Complete" }, { SystemExclusiveFunction.WriteError, "Write Error" }, { SystemExclusiveFunction.WriteErrorByProtect, "Write Error (Protect)" }, { SystemExclusiveFunction.WriteErrorByMemoryFull, "Write Error (Memory Full)" }, { SystemExclusiveFunction.WriteErrorByNoExpandMemory, "Write Error (No Expansion Memory)" } }; var function = (SystemExclusiveFunction)header.Function; string functionName; if (functionNames.TryGetValue(function, out functionName)) { Console.Error.WriteLine("Function = {0}", functionName); } else { Console.Error.WriteLine("Unknown function: {0}", function); } switch (header.Substatus1) { case 0x00: Console.WriteLine("Single"); break; case 0x20: Console.WriteLine("Multi"); break; case 0x10: Console.WriteLine("Drum Kit"); // K5000W only break; case 0x11: Console.WriteLine("Drum Inst"); // K5000W only break; default: Console.Error.WriteLine(string.Format("Unknown substatus1: {0:X2}", header.Substatus1)); break; } switch (header.Substatus2) { case 0x00: Console.WriteLine("Add Bank A"); break; case 0x01: Console.WriteLine("PCM Bank B"); // K5000W break; case 0x02: Console.WriteLine("Add Bank D"); break; case 0x03: Console.WriteLine("Exp Bank E"); break; case 0x04: Console.WriteLine("Exp Bank F"); break; default: Console.WriteLine("Substatus2 is first data byte"); break; } switch (function) { case SystemExclusiveFunction.OneBlockDump: Console.WriteLine("One Block Dump"); int toneNumber = message[8] + 1; Console.WriteLine($"Tone No = {toneNumber} ({message[8]})"); break; case SystemExclusiveFunction.AllBlockDump: Console.WriteLine("All Block Dump"); break; default: Console.WriteLine($"Unknown function: {function}"); break; } if (function == SystemExclusiveFunction.AllBlockDump) { var patchMapData = new byte[PatchMap.Size]; Array.Copy(message, SystemExclusiveHeader.DataSize, patchMapData, 0, PatchMap.Size); var patchMap = new PatchMap(patchMapData); Console.WriteLine("Patches included:"); for (var i = 0; i < PatchMap.PatchCount; i++) { if (patchMap[i]) { Console.Write(i + 1); Console.Write(" "); } } Console.WriteLine(); var dataLength = message.Length - SystemExclusiveHeader.DataSize - PatchMap.Size; var data = new byte[dataLength]; Array.Copy(message, SystemExclusiveHeader.DataSize + PatchMap.Size, data, 0, dataLength); //Console.WriteLine(Util.HexDump(data)); var offset = 0; byte checksum = data[offset]; Console.WriteLine($"checksum = {checksum:X2}"); offset += 1; } // Single additive patch for bank A or D: if (header.Substatus1 == 0x00 && (header.Substatus2 == 0x00 || header.Substatus2 == 0x02)) { var dataLength = message.Length - SystemExclusiveHeader.DataSize - PatchMap.Size; var data = new byte[dataLength]; Array.Copy(message, SystemExclusiveHeader.DataSize + PatchMap.Size, data, 0, dataLength); //Console.WriteLine(Util.HexDump(data)); // Chop the data into individual buffers based on the declared sizes var offset = 0; byte checksum = data[offset]; Console.WriteLine($"checksum = {checksum:X2}"); offset += 1; var commonData = new byte[SingleCommonSettings.DataSize]; Array.Copy(data, offset, commonData, 0, SingleCommonSettings.DataSize); //Console.WriteLine(Util.HexDump(commonData)); offset += SingleCommonSettings.DataSize; var patch = new SinglePatch(data); Console.WriteLine($"Name = {patch.SingleCommon.Name}"); } }
public int DumpPatches(string outputFormat) { var offset = 8; // skip to the tone map byte[] buffer; (buffer, offset) = Util.GetNextBytes(this.data, offset, PatchMap.Size); var patchMap = new PatchMap(buffer); List <int> patchNumbers = new List <int>(); var patchCount = 0; for (var i = 0; i < PatchMap.PatchCount; i++) { if (patchMap[i]) { patchCount += 1; //Console.Write(i + 1); //Console.Write(" "); patchNumbers.Add(i); } } var minimumPatchSize = SingleCommonSettings.DataSize + 2 * KSynthLib.K5000.Source.DataSize; var totalPatchSize = 0; // the total size of all the single patches var allPatchInfos = new List <PatchInfo>(); var singlePatches = new List <SinglePatch>(); foreach (var patchNumber in patchNumbers) { var startOffset = offset; // save the current offset because we need to copy more bytes later var sizeToRead = Math.Max(minimumPatchSize, this.data.Length - offset); // We don't know yet how many bytes the patch is, but it is at least the minimum size (buffer, offset) = Util.GetNextBytes(this.data, offset, sizeToRead); // the offset has now been updated past the read size, so need to adjust it back later //Console.Error.WriteLine(Util.HexDump(buffer)); //Console.Error.WriteLine($"checksum = {buffer[0]:X2}H"); var patch = new SinglePatch(buffer); // Find out how many PCM and ADD sources var pcmCount = 0; var addCount = 0; foreach (var source in patch.Sources) { if (source.IsAdditive) { addCount += 1; } else { pcmCount += 1; } } // Figure out the total size of the single patch based on the counts var patchSize = 1 + SingleCommonSettings.DataSize // includes the checksum + patch.Sources.Length * KSynthLib.K5000.Source.DataSize // all sources have this part + addCount * AdditiveKit.DataSize; //Console.WriteLine($"{pcmCount}PCM {addCount}ADD size={patchSize} bytes"); offset = startOffset; // back up to the start of the patch data // Read the whole patch now that we know its size //Console.WriteLine($"About to read {patchSize} bytes starting from offset {offset:X4}h"); (buffer, offset) = Util.GetNextBytes(this.data, offset, patchSize); totalPatchSize += patchSize; singlePatches.Add(patch); } foreach (var patch in singlePatches) { if (outputFormat.Equals("text")) { Console.WriteLine(patch); } else if (outputFormat.Equals("json")) { string jsonString = JsonConvert.SerializeObject( patch, Newtonsoft.Json.Formatting.Indented, new Newtonsoft.Json.Converters.StringEnumConverter() ); Console.WriteLine(jsonString); } } return(0); }
static int Main(string[] args) { if (args.Length < 2) { System.Console.WriteLine("Usage: K5KTool cmd filename.syx"); return(1); } string command = args[0]; string fileName = args[1]; string patchName = ""; if (args.Length > 2) { patchName = args[2]; } byte[] fileData = File.ReadAllBytes(fileName); System.Console.WriteLine($"SysEx file: '{fileName}' ({fileData.Length} bytes)"); List <byte[]> messages = Util.SplitBytesByDelimiter(fileData, Constants.SystemExclusiveTerminator); System.Console.WriteLine($"Got {messages.Count} messages"); foreach (byte[] message in messages) { SystemExclusiveHeader header = new SystemExclusiveHeader(message); //System.Console.WriteLine(Util.HexDump(header.Data)); System.Console.WriteLine(header.ToString()); int headerLength = header.Data.Length; // Examine the header to see what kind of message this is: SystemExclusiveFunction function = (SystemExclusiveFunction)header.Function; if (function == SystemExclusiveFunction.AllPatchDataDump) { // sub2: 0=I or E, 20H=i or e singles if (header.Substatus2 == 0x00 || header.Substatus2 == 0x20) { int offset = headerLength; for (int i = 0; i < NumSingles; i++) { byte[] singleData = new byte[SinglePatch.DataSize]; Buffer.BlockCopy(message, offset, singleData, 0, SinglePatch.DataSize); System.Console.WriteLine("INGOING SINGLE DATA = \n" + Util.HexDump(singleData)); SinglePatch single = new SinglePatch(singleData); System.Console.WriteLine(single.ToString()); byte[] sysExData = single.ToData(); System.Console.WriteLine("OUTCOMING SINGLE DATA = \n" + Util.HexDump(sysExData)); (bool result, int diffIndex) = Util.ByteArrayCompare(singleData, sysExData); System.Console.WriteLine(String.Format("match = {0}, diff index = {1}", result ? "YES :-)" : "NO :-(", diffIndex)); offset += SinglePatch.DataSize; } } else if (header.Substatus2 == 0x40) { System.Console.WriteLine("Multis not handled yet"); return(1); } } else if (function == SystemExclusiveFunction.OnePatchDataDump) { System.Console.WriteLine("One patch dumps not handled yet"); return(1); } } return(0); }