private static void ProcessMessage(byte[] message) { SystemExclusiveHeader header = new SystemExclusiveHeader(message); Console.WriteLine(header); Dictionary <SystemExclusiveFunction, string> functionNames = new Dictionary <SystemExclusiveFunction, string>() { { SystemExclusiveFunction.AllPatchDataDump, "All Patch Data Dump" }, { SystemExclusiveFunction.AllPatchDumpRequest, "All Patch Data Dump Request" }, { SystemExclusiveFunction.BlockPatchDataDump, "Block Patch Data Dump" }, { SystemExclusiveFunction.BlockPatchDumpRequest, "Block Patch Data Dump Request" }, { SystemExclusiveFunction.EditBufferDump, "Edit Buffer Dump" }, { SystemExclusiveFunction.OnePatchDataDump, "One Patch Data Dump" }, { SystemExclusiveFunction.OnePatchDumpRequest, "One Patch Data Dump Request" }, { SystemExclusiveFunction.ParameterSend, "Parameter Send" }, { SystemExclusiveFunction.ProgramChange, "Program Change" }, { SystemExclusiveFunction.WriteComplete, "Write Complete" }, { SystemExclusiveFunction.WriteError, "Write Error" }, { SystemExclusiveFunction.WriteErrorNoCard, "Write Error (No Card)" }, { SystemExclusiveFunction.WriteErrorProtect, "Write Error (Protect)" } }; SystemExclusiveFunction function = (SystemExclusiveFunction)header.Function; string functionName = ""; if (functionNames.TryGetValue(function, out functionName)) { Console.WriteLine($"Function = {functionName}"); } else { Console.WriteLine($"Unknown function: {function}"); } }
private static DumpHeader Identify(byte[] fileData) { Console.WriteLine($"File data length = {fileData.Length} bytes"); // Assume that we have at least one header's worth of data var header = new SystemExclusiveHeader(fileData); return(new DumpHeader(Cardinality.Block, BankIdentifier.A, PatchKind.Single)); }
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 static int RunListAndReturnExitCode(ListOptions opts) { string fileName = opts.FileName; byte[] message = File.ReadAllBytes(fileName); string namePart = new DirectoryInfo(fileName).Name; DateTime timestamp = File.GetLastWriteTime(fileName); string timestampString = timestamp.ToString("yyyy-MM-dd hh:mm:ss"); Console.WriteLine($"System Exclusive file: '{namePart}' ({timestampString}, {message.Length} bytes)"); SystemExclusiveHeader header = new SystemExclusiveHeader(message); // TODO: Check the SysEx file header for validity // Extract the patch bytes (discarding the SysEx header and terminator) int dataLength = message.Length - SystemExclusiveHeader.DataSize - 1; byte[] data = new byte[dataLength]; Array.Copy(message, SystemExclusiveHeader.DataSize, data, 0, dataLength); // TODO: Split the data into chunks representing single, multi, drum, and effect data //Console.WriteLine($"Total data length (with/without header): {message.Length}/{data.Length} bytes"); string outputFormat = opts.Output; if (outputFormat.Equals("text")) { Console.WriteLine(MakeTextList(data, namePart)); return(0); } else if (outputFormat.Equals("html")) { Console.WriteLine(MakeHtmlList(data, namePart)); return(0); } else { Console.WriteLine($"Unknown output format: '{outputFormat}'"); return(-1); } }
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 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); }
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}"); } }