Пример #1
0
        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}");
            }
        }
Пример #2
0
        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));
        }
Пример #3
0
        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);
        }
Пример #4
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);
        }
Пример #5
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);
            }
        }
Пример #6
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());
        }
Пример #7
0
        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);
        }
Пример #8
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);
        }
Пример #9
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}");
            }
        }