Novation SYSEX Synth bank patch dump C# source

By | December 11, 2019
using System;
using System.IO;
using System.Text;
using System.Text.RegularExpressions;
using System.Diagnostics;

namespace CircuitBank2Patch
{
    class Program
    {
        static void Main(string[] args)
        {

            string startPath ="";
            string startfolderPath = "";
            string startfileName = "";
            string startfileExtension = "";
            Console.OutputEncoding = System.Text.Encoding.GetEncoding(28591);
            Console.Title = "Novation Circuit - Synth Bank Sysex Patch Dump";
            string title = @"
                _________ .__                     .__  __   
                \_   ___ \|__|______   ____  __ __|__|/  |_ 
                /    \  \/|  \_  __ \_/ ___\|  |  \  \   __\
                \     \___|  ||  | \/\  \___|  |  /  ||  |  
                 \______  /__||__|    \___  >____/|__||__|  
                        \/                \/                
                --------------------------------------------
          Novation Circuit Synth Bank SYSEX Patch Dump Utility v1.0

 This program will dump all patches from a Cicruit Sysex (.syx) bank
 to a subdirectory named BankName_Extracted located wherever your bank 
 file originates.

  .----------------------------------------------------------------------.
 | Notes:                                                                |
 | This for Novation Circuit >>SYNTH bank .syx files ONLY<<.             |
 | The original bank file is NOT modified in any way.                    |
 | If your bank contains patches with duplicate names, the file names    |
 |  for those patches will have a number appended to the filename.       |
 | If the destination directory already contains patches, any new files  |
 | created will have a number appended to them. No files are deleted.    |
 `-----------------------------------------------------------------------'

 Usage: Drag & Drop your Circuit Patch Bank .syx file onto this EXE.

 ----------------------------------------------------------------------

";

            Console.WriteLine(title);
            Console.WriteLine("Press any key to continue or press ESC to abort");
            ConsoleKeyInfo info = Console.ReadKey();
            if (info.Key == ConsoleKey.Escape)
            {
                Console.WriteLine("ESC pressed. Program Aborted, nothing will be processed.");
                System.Threading.Thread.Sleep(5000);
                System.Environment.Exit(0);

            }
            if (args.Length > 0 && File.Exists(args[0]))
            {
                startPath = args[0];
                startfolderPath = Path.GetDirectoryName(startPath);
                startfileName = Path.GetFileNameWithoutExtension(startPath);
                startfileExtension = Path.GetExtension(startPath);
                //Console.WriteLine("{0}, {1}, {2}, {3}", startfileName, startPath, startfileExtension, startfolderPath);
                Console.WriteLine("\n" +
                    "  Bank name: {0}\n" +
                    "  Bank Directory: {1}\n" +
                    "  Patches Destination Directory: {2}\n\n", startfileName, startfolderPath, startfolderPath + @"\" + startfileName + @"_Extracted\",
                    "-------------------------------------");
                System.Threading.Thread.Sleep(5000);

            }


            if (args.Length <= 0)
            {
                Console.WriteLine("\nNo file detected: To use this program, Drag and Drop your Bank directly onto the exe. \n\n Exiting...");
                System.Threading.Thread.Sleep(5000);
                System.Environment.Exit(0);
            }

            string filePath = startfolderPath;
            string outputPath = filePath + @"\" + startfileName + @"_Extracted\";
            System.IO.Directory.CreateDirectory(outputPath);
            FileStream filename;
            filename = new FileStream(startPath, FileMode.Open);
            var buffer = new byte[350];
            //int bytesRead = 0; //replaced by _ discard 
            int filecount = 0;
            int initialpatch = 0;
            int renamecount = 1;
            while ((_ = filename.Read(buffer, 0, buffer.Length)) > 0)
            {

                filecount++;
                FileStream singlePatch;
                singlePatch = new FileStream(outputPath + @"patch" + filecount + ".syx", FileMode.Append);
                singlePatch.Write(buffer, 0, buffer.Length);
                singlePatch.Close();
            }

            while (filecount > 0)  //fix bytes for compatibility
            {
                FileStream renamePatch;
                string fileforRename = outputPath + @"patch" + renamecount + ".syx";
                renamePatch = new FileStream(fileforRename, FileMode.Open, FileAccess.ReadWrite);
                renamePatch.Seek(0x07, SeekOrigin.Begin);   //replace by 0x07 with value 0x00 for librarian compatibility ..in bank it increase by patch #
                renamePatch.WriteByte(0x00);
                renamePatch.Seek(0x06, SeekOrigin.Begin);   //replace by 0x06 with value 0x00 for librarian compatibility ..in bank it increase by patch #
                renamePatch.WriteByte(0x00);
                renamePatch.Seek(0x09, SeekOrigin.Begin);   //start byte location of patch name
                var data = new byte[16];                    //patch name can be up to 16 chars long
                renamePatch.Read(data, 0, 16);              //read all 16 bytes as new byte[]
                string convertbytes = Encoding.UTF8.GetString(data, 0, data.Length).Trim(); //convert byte[] (data) containing patch name to string
                string converted = convertbytes.Replace(" ", "_"); //replace whitespace with underscore for potential program, path, compatibility import issues
                if (converted.Contains("Initial_Patch")) { converted += "_" + initialpatch; initialpatch++; } //handle initial patches seperately
                //Console.WriteLine("{0}", converted.Trim());
                renamePatch.Close();

                //HAVE PATCH NAME NOW CHECK FOR FILE AND RENAME/MOVE TO PATCHNAME.SYX
                //HANDLE OUTPUT HERE

                //Console.WriteLine("{0}", GetUniqueFilePath(fullfilePath));
                string fullfilePath = outputPath + converted.Trim() + ".syx";
                string uniquePath = GetUniqueFilePath(fullfilePath);
                File.Move(fileforRename, uniquePath);  //output file with dupecheck and rename 
                string outFile = Path.GetFileNameWithoutExtension(uniquePath);
                if (outFile.Contains(@"(")) { outFile = outFile + " - Possible Dupilcate"; }
                Console.WriteLine("  Written: {0}", @".\" + startfileName + @"_Extracted\" + outFile );
                System.Threading.Thread.Sleep(50);
                renamecount++;
                filecount--;

            }

            filename.Close();
            Console.WriteLine("Dump completed. Press SPACE to open folder or any other key to Exit.");
            ConsoleKeyInfo info2 = Console.ReadKey();
            if (info2.Key == ConsoleKey.Spacebar)
            {
                Process.Start("explorer.exe", outputPath);
                System.Environment.Exit(0);

            }


        }

        public static string GetUniqueFilePath(string filePath)
        {
            if (File.Exists(filePath))
            {
                string folderPath = Path.GetDirectoryName(filePath);
                string fileName = Path.GetFileNameWithoutExtension(filePath);
                string fileExtension = Path.GetExtension(filePath);
                int number = 1;

                Match regex = Regex.Match(fileName, @"^(.+) \((\d+)\)$");

                if (regex.Success)
                {
                    fileName = regex.Groups[1].Value;
                    number = int.Parse(regex.Groups[2].Value);
                }

                do
                {
                    number++;
                    string newFileName = $"{fileName} ({number}){fileExtension}";
                    filePath = Path.Combine(folderPath, newFileName);
                }
                while (File.Exists(filePath));
            }

            return filePath;
        }

    }
}

Leave a Reply

Your email address will not be published. Required fields are marked *