示例#1
0
        static void Main(string[] args)
        {
            bool        showLicense    = false;
            bool        showHelp       = false;
            eDumpFormat dumpFormat     = eDumpFormat.FormatText;
            bool        useVbr         = false;
            string      mode           = "";
            string      outputLocation = "";
            string      prefixLocation = null;
            string      audioId        = "";
            string      jsonFile       = "tonies.json";

            int bitRate = 96;

            var p = new OptionSet {
                { "m|mode=", "Operating mode: info, decode, encode", (string n) => mode = n },
                { "o|output=", "Location where to write the file(s) to", (string r) => outputLocation = r },
                { "p|prefix=", "Location where to find prefix files", (string r) => prefixLocation = r },
                { "i|id=", "Set AudioID for encoding (default: current time)", (string r) => audioId = r },
                { "b|bitrate=", "Set opus bit rate (default: " + bitRate + " kbps)", (int r) => bitRate = r },
                { "vbr", "Use VBR encoding", r => useVbr = true },
                { "j|json=", "Set JSON file/URL with details about tonies", (string r) => jsonFile = r },
                { "f|format=", "Output details as: csv, json or text", v => { switch (v)
                                                                              {
                                                                              case "csv":  dumpFormat = eDumpFormat.FormatCSV; break;

                                                                              case "json":  dumpFormat = eDumpFormat.FormatJSON; break;

                                                                              case "text":  dumpFormat = eDumpFormat.FormatText; break;
                                                                              }
                  } },
                { "v", "increase debug message verbosity", v => { if (v != null)
                                                                  {
                                                                      ++Verbosity;
                                                                  }
                  } },
                { "h|help", "show this message and exit", h => showHelp = true },
                { "license", "show licenses and disclaimer", h => showLicense = true },
            };

            List <string> extra;

            try
            {
                extra = p.Parse(args);
            }
            catch (OptionException e)
            {
                Console.Write("Teddy.exe: ");
                Console.WriteLine(e.Message);
                Console.WriteLine("Try `Teddy.exe --help' for more information.");
                return;
            }

            if (showLicense)
            {
                ShowLicense(p);
                return;
            }

            if (showHelp)
            {
                ShowHelp(p);
                return;
            }

            LoadJson(jsonFile);

            switch (mode)
            {
            default:
                ShowHelp(p);
                return;

            case "info":
            {
                if (extra.Count < 1 || (!Directory.Exists(extra[0]) && !File.Exists(extra[0])))
                {
                    Console.WriteLine("Error: You must specify a file");
                    return;
                }

                switch (dumpFormat)
                {
                case eDumpFormat.FormatCSV:
                    if (extra.Count > 1 || Directory.Exists(extra[0]))
                    {
                        Console.WriteLine("UID;AudioID;AudioDate;HeaderLength;HeaderOK;Padding;AudioLength;AudioLengthCheck;AudioHash;AudioHashCheck;Chapters;Segments;MinSegmentsPerPage;MaxSegmentsPerPage;SegLengthSum;HighestGranule;Time;MinGranules;MaxGranules;MinTime;MaxTime;");
                    }
                    break;

                case eDumpFormat.FormatJSON:
                    Console.WriteLine("[");
                    break;

                case eDumpFormat.FormatText:
                    Console.WriteLine("[Mode: dump information]");
                    break;
                }

                List <string> files = new List <string>();

                foreach (string file in extra)
                {
                    if (Directory.Exists(file))
                    {
                        FindTonieFiles(files, file);
                    }
                    else
                    {
                        if (!File.Exists(file))
                        {
                            Console.WriteLine("Error: file '" + file + "' does not exist");
                            return;
                        }
                        files.Add(file);
                    }
                }

                bool first = true;
                foreach (string file in files.ToArray())
                {
                    try
                    {
                        TonieAudio dumpFile = TonieAudio.FromFile(file);

                        dumpFile.CalculateStatistics(out long segCount, out long segLength, out int minSegs, out int maxSegs, out ulong minGranule, out ulong maxGranule, out ulong highestGranule);
                        string        uidrev = new FileInfo(file).Directory.Name + new FileInfo(file).Name;
                        List <string> groups = (from Match m in Regex.Matches(uidrev, @"[A-F0-9]{2}") select m.Value).ToList();
                        groups.Reverse();
                        string uid  = string.Join("", groups.ToArray());
                        var    date = DateTimeOffset.FromUnixTimeSeconds(dumpFile.Header.AudioId);

                        switch (dumpFormat)
                        {
                        case eDumpFormat.FormatCSV:
                        {
                            Console.Write(uid + ";");
                            Console.Write(dumpFile.Header.AudioId.ToString("X8") + ";");
                            Console.Write(date.ToString("yyyy'-'MM'-'dd'T'HH':'mm':'ss") + ";");
                            Console.Write(dumpFile.HeaderLength + ";");
                            Console.Write(((dumpFile.HeaderLength != 0xFFC) ? "[WARNING: EXTRA DATA]" : "[OK]") + ";");
                            Console.Write(dumpFile.Header.Padding.Length + ";");
                            Console.Write(dumpFile.Header.AudioLength + ";");
                            Console.Write((dumpFile.Header.AudioLength == dumpFile.Audio.Length ? "[OK]" : "[INCORRECT]") + ";");
                            Console.Write(BitConverter.ToString(dumpFile.Header.Hash).Replace("-", "") + ";");
                            Console.Write((dumpFile.HashCorrect ? "[OK]" : "[INCORRECT]") + ";");
                            foreach (var offset in dumpFile.Header.AudioChapters)
                            {
                                Console.Write(offset + " ");
                            }
                            Console.Write(";");

                            Console.Write(segCount + ";");
                            Console.Write(minSegs + ";");
                            Console.Write(maxSegs + ";");
                            Console.Write(segLength + ";");
                            Console.Write(highestGranule + ";");
                            Console.Write(TonieAudio.FormatGranule(highestGranule) + ";");
                            Console.Write(minGranule + ";");
                            Console.Write(maxGranule + ";");
                            Console.Write((1000 * minGranule / 48000.0f) + ";");
                            Console.Write((1000 * maxGranule / 48000.0f) + ";");
                            Console.WriteLine();
                            break;
                        }

                        case eDumpFormat.FormatText:
                        {
                            Console.WriteLine("Dump of " + dumpFile.Filename + " (UID " + uid + "):");

                            Console.WriteLine("  Header: AudioID     0x" + dumpFile.Header.AudioId.ToString("X8") + " (" + date.ToString("yyyy'-'MM'-'dd'T'HH':'mm':'ss") + ")");

                            string[] titles = null;
                            var      found  = TonieInfos.Where(t => t.AudioIds.Contains(dumpFile.Header.AudioId));
                            if (found.Count() > 0)
                            {
                                var info = found.First();
                                titles = info.Tracks;

                                Console.WriteLine("  Header: JSON Name   '" + info.Title + "'");
                            }
                            Console.WriteLine("  Header: Length      0x" + dumpFile.HeaderLength.ToString("X8") + " " + ((dumpFile.HeaderLength != 0xFFC) ? " [WARNING: EXTRA DATA]" : "[OK]"));
                            Console.WriteLine("  Header: Padding     0x" + dumpFile.Header.Padding.Length.ToString("X8"));
                            Console.WriteLine("  Header: AudioLen    0x" + dumpFile.Header.AudioLength.ToString("X8") + " " + (dumpFile.Header.AudioLength == dumpFile.Audio.Length ? "[OK]" : "[INCORRECT]"));
                            Console.WriteLine("  Header: Checksum    " + BitConverter.ToString(dumpFile.Header.Hash).Replace("-", "") + " " + (dumpFile.HashCorrect ? "[OK]" : "[INCORRECT]"));
                            Console.WriteLine("  Header: Chapters    ");

                            TimeSpan prevTime = new TimeSpan();
                            for (int track = 1; track <= dumpFile.Header.AudioChapters.Length; track++)
                            {
                                uint off = dumpFile.GetHighestPage();

                                if (track < dumpFile.Header.AudioChapters.Length)
                                {
                                    off = dumpFile.Header.AudioChapters[track];
                                }
                                ulong  granule      = dumpFile.GetGranuleByPage(off);
                                string lengthString = "@" + off;

                                if (granule != ulong.MaxValue)
                                {
                                    TimeSpan trackOffset = TimeSpan.FromSeconds(granule / 48000.0f);
                                    lengthString = (trackOffset - prevTime).ToString(@"mm\:ss\.ff");
                                    prevTime     = trackOffset;
                                }

                                string title = "";

                                if (titles != null && track - 1 < titles.Length)
                                {
                                    title = titles[track - 1];
                                }
                                Console.WriteLine("    Track #" + track.ToString("00") + "  " + lengthString + "  " + title);
                            }

                            Console.WriteLine("  Ogg: Segments       " + segCount + " (min: " + minSegs + " max: " + maxSegs + " per OggPage)");
                            Console.WriteLine("  Ogg: net payload    " + segLength + " byte");
                            Console.WriteLine("  Ogg: granules       total: " + highestGranule + " (" + TonieAudio.FormatGranule(highestGranule) + " hh:mm:ss.ff)");
                            Console.WriteLine("  Ogg: granules/page  min: " + minGranule + " max: " + maxGranule + " (" + (1000 * minGranule / 48000.0f) + "ms - " + (1000 * maxGranule / 48000.0f) + "ms)");
                            Console.WriteLine();
                            break;
                        }

                        case eDumpFormat.FormatJSON:
                        {
                            if (!first)
                            {
                                Console.WriteLine(",");
                            }
                            Console.WriteLine("  {");
                            Console.WriteLine("    \"uid\": \"" + uid + "\",");
                            Console.WriteLine("    \"audio_id\": \"" + dumpFile.Header.AudioId.ToString("X8") + "\",");
                            Console.WriteLine("    \"audio_date\": \"" + date.ToString("yyyy'-'MM'-'dd'T'HH':'mm':'ss") + "\",");
                            Console.WriteLine("    \"header_length\": " + dumpFile.HeaderLength + ",");
                            Console.WriteLine("    \"header_ok\": \"" + ((dumpFile.HeaderLength != 0xFFC) ? "FALSE" : "TRUE") + "\",");
                            Console.WriteLine("    \"padding\": " + dumpFile.Header.Padding.Length + ",");
                            Console.WriteLine("    \"audio_length\": " + dumpFile.Header.AudioLength + ",");
                            Console.WriteLine("    \"audio_length_check\": \"" + (dumpFile.Header.AudioLength == dumpFile.Audio.Length ? "TRUE" : "FALSE") + "\",");
                            Console.WriteLine("    \"audio_hash\": \"" + BitConverter.ToString(dumpFile.Header.Hash).Replace("-", "") + "\",");
                            Console.WriteLine("    \"audio_hash_check\": \"" + (dumpFile.HashCorrect ? "TRUE" : "FALSE") + "\",");
                            Console.Write("    \"chapters\": [ 0");
                            foreach (var offset in dumpFile.Header.AudioChapters)
                            {
                                Console.Write(", " + offset);
                            }
                            Console.WriteLine(" ],");
                            Console.WriteLine("    \"segments\": " + segCount + ",");
                            Console.WriteLine("    \"min_segments_per_page\": " + minSegs + ",");
                            Console.WriteLine("    \"max_segments_per_page\": " + maxSegs + ",");
                            Console.WriteLine("    \"segment_length_sum\": " + segLength + ",");
                            Console.WriteLine("    \"highest_granule\": " + highestGranule + ",");
                            Console.WriteLine("    \"time\": \"" + TonieAudio.FormatGranule(highestGranule) + "\",");
                            Console.WriteLine("    \"min_granules\": " + minGranule + ",");
                            Console.WriteLine("    \"max_granules\": " + maxGranule + ",");
                            Console.WriteLine("    \"min_time\": " + (1000 * minGranule / 48000.0f) + ",");
                            Console.WriteLine("    \"max_time\": " + (1000 * maxGranule / 48000.0f) + "");
                            Console.WriteLine("  }");

                            break;
                        }
                        }
                    }
                    catch (FileNotFoundException ex)
                    {
                        Console.WriteLine("File not found: " + file);
                    }
                    catch (InvalidDataException ex)
                    {
                        Console.WriteLine("File corrupt: " + file);
                    }
                    catch (Exception e)
                    {
                        Console.WriteLine();
                        Console.WriteLine("[ERROR] Failed to process '" + file + "'");
                        Console.WriteLine("   Exception:  " + e.GetType());
                        Console.WriteLine("   Message:    " + e.Message);
                        Console.WriteLine("   Stacktrace: " + e.StackTrace);
                    }

                    if (first)
                    {
                        first = false;
                    }
                }

                switch (dumpFormat)
                {
                case eDumpFormat.FormatCSV:
                    break;

                case eDumpFormat.FormatJSON:
                    Console.WriteLine("]");
                    break;

                case eDumpFormat.FormatText:
                    break;
                }
                break;
            }

            case "decode":
            {
                if (extra.Count < 1 || (!Directory.Exists(extra[0]) && !File.Exists(extra[0])))
                {
                    Console.WriteLine("Error: You must specify a file");
                    return;
                }

                List <string> files = new List <string>();

                foreach (string file in extra)
                {
                    if (Directory.Exists(file))
                    {
                        FindTonieFiles(files, file);
                    }
                    else
                    {
                        if (!File.Exists(file))
                        {
                            Console.WriteLine("Error: file '" + file + "' does not exist");
                            return;
                        }
                        files.Add(file);
                    }
                }

                Console.WriteLine("[Mode: decode file]");

                foreach (string file in files.ToArray())
                {
                    try
                    {
                        Console.WriteLine("Dumping '" + file + "'");
                        TonieAudio dump2        = TonieAudio.FromFile(file);
                        string     inFile       = new FileInfo(file).Name;
                        string     inDir        = new FileInfo(file).DirectoryName;
                        string     outDirectory = !string.IsNullOrEmpty(outputLocation) ? outputLocation : inDir;

                        if (!Directory.Exists(outDirectory))
                        {
                            Console.WriteLine("Error: Output directory '" + outDirectory + "' does not exist");
                            return;
                        }
                        string outFile = outDirectory + Path.DirectorySeparatorChar + inFile;

                        try
                        {
                            File.WriteAllBytes(outFile + ".ogg", dump2.Audio);
                            File.WriteAllText(outFile + ".cue", BuildCueSheet(dump2), Encoding.UTF8);
                        }
                        catch (Exception ex)
                        {
                            Console.WriteLine("[ERROR] Failed to write file '" + outFile + ".occ/.cue'");
                            Console.WriteLine("   Message:    " + ex.Message);
                        }
                        Console.WriteLine("Written content to " + outFile + ".ogg/.cue");
                    }
                    catch (FileNotFoundException ex)
                    {
                        Console.WriteLine("File not found: " + file);
                    }
                    catch (InvalidDataException ex)
                    {
                        Console.WriteLine("File corrupt: " + file);
                    }
                    catch (Exception e)
                    {
                        Console.WriteLine();
                        Console.WriteLine("[ERROR] Failed to process '" + file + "'");
                        Console.WriteLine("   Exception:  " + e.GetType());
                        Console.WriteLine("   Message:    " + e.Message);
                        Console.WriteLine("   Stacktrace: " + e.StackTrace);
                    }
                }
                break;
            }

            case "encode":
                Console.WriteLine("[Mode: encode, " + bitRate + " kbps, " + (useVbr ? "VBR" : "CBR") + "]");

                if (extra.Count < 1)
                {
                    Console.WriteLine("Error: You must specify a directory or files to encode");
                    return;
                }

                /*
                 * if ((bitRate % 24) != 0)
                 * {
                 *  Console.WriteLine("Error: You must specify a multiple of 24 kbps, else block alignment in output file would produce incompatible files");
                 *  return;
                 * }*/

                uint id = (uint)DateTimeOffset.Now.ToUnixTimeSeconds();
                if (audioId != "")
                {
                    if (audioId.Trim().StartsWith("0x"))
                    {
                        if (!uint.TryParse(audioId.Replace("0x", ""), System.Globalization.NumberStyles.HexNumber, null, out id))
                        {
                            Console.WriteLine("Error: You must specify the AudioID as hex value like 0x5E034216 or as decimal number like 1577271830");
                            return;
                        }
                    }
                    else
                    {
                        if (!uint.TryParse(audioId, System.Globalization.NumberStyles.Integer, null, out id))
                        {
                            Console.WriteLine("Error: You must specify the AudioID as hex value like 0x5E034216 or as decimal number like 1577271830");
                            return;
                        }
                    }
                }

                try
                {
                    string outLocationEncode = ((!string.IsNullOrEmpty(outputLocation)) ? outputLocation : ".");
                    string outFile;

                    if (!Directory.Exists(outLocationEncode))
                    {
                        string baseDirOutFile = new FileInfo(outLocationEncode).DirectoryName;
                        if (!Directory.Exists(baseDirOutFile))
                        {
                            Console.WriteLine("Error: Specified output directory '" + outLocationEncode + "' does not exist and file '" + baseDirOutFile + "' not reachable.");
                            return;
                        }
                        outFile = outLocationEncode;
                    }
                    else
                    {
                        outFile = outLocationEncode + Path.DirectorySeparatorChar + "500304E0";
                    }

                    TonieAudio generated = new TonieAudio(extra.ToArray(), id, bitRate * 1000, useVbr, prefixLocation);
                    try
                    {
                        File.WriteAllBytes(outFile, generated.FileContent);
                    }
                    catch (Exception ex)
                    {
                        Console.WriteLine("[ERROR] Failed to write file '" + outFile + "'");
                        Console.WriteLine("   Message:    " + ex.Message);
                    }

                    Console.WriteLine("");
                    Console.WriteLine("Written content to " + outFile);
                }
                catch (FileNotFoundException ex)
                {
                    Console.WriteLine("[ERROR] Failed to process due to a missing file");
                    Console.WriteLine("   Message:    " + ex.Message);
                }
                catch (InvalidDataException ex)
                {
                    Console.WriteLine("[ERROR] Failed to process due to an invalid file");
                    Console.WriteLine("   Message:    " + ex.Message);
                }
                catch (TonieAudio.EncodingException ex)
                {
                    Console.WriteLine("[ERROR] Failed to encode audio");
                    Console.WriteLine("   Message:    " + ex.Message);
                }
                catch (Exception e)
                {
                    Console.WriteLine();
                    Console.WriteLine("[ERROR] Failed to process");
                    Console.WriteLine("   Exception:  " + e.GetType());
                    Console.WriteLine("   Message:    " + e.Message);
                    Console.WriteLine("   Stacktrace: " + e.StackTrace);
                }
                break;
            }
        }
示例#2
0
        public static bool DumpInfo(StringBuilder message, eDumpFormat dumpFormat, string file, TonieData[] tonieInfos, string customName = null)
        {
            TonieAudio dumpFile = TonieAudio.FromFile(file);

            dumpFile.CalculateStatistics(out long segCount, out long segLength, out int minSegs, out int maxSegs, out ulong minGranule, out ulong maxGranule, out ulong highestGranule);
            string        uidrev = new FileInfo(file).Directory.Name + new FileInfo(file).Name;
            List <string> groups = (from Match m in Regex.Matches(uidrev, @"[A-F0-9]{2}") select m.Value).ToList();

            groups.Reverse();
            string uid = string.Join("", groups.ToArray());

            string dateExtra = "";
            int    id        = dumpFile.Header.AudioId;

            if (id < 0x50000000)
            {
                dateExtra = "custom file, real date ";
                id       += 0x50000000;
            }
            var  date  = DateTimeOffset.FromUnixTimeSeconds(id);
            bool first = false;

            switch (dumpFormat)
            {
            case eDumpFormat.FormatCSV:
            {
                message.Append(uid + ";");
                message.Append(dumpFile.Header.AudioId.ToString("X8") + ";");
                message.Append(date.ToString("yyyy'-'MM'-'dd'T'HH':'mm':'ss") + ";");
                message.Append(dumpFile.HeaderLength + ";");
                message.Append(((dumpFile.HeaderLength != 0xFFC) ? "[WARNING: EXTRA DATA]" : "[OK]") + ";");
                message.Append(dumpFile.Header.Padding.Length + ";");
                message.Append(dumpFile.Header.AudioLength + ";");
                message.Append((dumpFile.Header.AudioLength == dumpFile.Audio.Length ? "[OK]" : "[INCORRECT]") + ";");
                message.Append(BitConverter.ToString(dumpFile.Header.Hash).Replace("-", "") + ";");
                message.Append((dumpFile.HashCorrect ? "[OK]" : "[INCORRECT]") + ";");
                foreach (var offset in dumpFile.Header.AudioChapters)
                {
                    message.Append(offset + " ");
                }
                message.Append(";");

                message.Append(segCount + ";");
                message.Append(minSegs + ";");
                message.Append(maxSegs + ";");
                message.Append(segLength + ";");
                message.Append(highestGranule + ";");
                message.Append(TonieAudio.FormatGranule(highestGranule) + ";");
                message.Append(minGranule + ";");
                message.Append(maxGranule + ";");
                message.Append((1000 * minGranule / 48000.0f) + ";");
                message.Append((1000 * maxGranule / 48000.0f) + ";");
                message.AppendLine();
                break;
            }

            case eDumpFormat.FormatText:
            {
                message.AppendLine("Dump of " + dumpFile.Filename + " (UID " + uid + "):");
                message.AppendLine("  Header: AudioID     0x" + dumpFile.Header.AudioId.ToString("X8") + " (" + dateExtra + date.ToString("yyyy'-'MM'-'dd'T'HH':'mm':'ss") + ")");

                string[]  titles         = null;
                string    hashString     = BitConverter.ToString(dumpFile.Header.Hash).Replace("-", "");
                var       found          = tonieInfos.Where(t => t.Hash.Contains(hashString));
                TonieData info           = null;
                string    infoHashString = null;
                int       infoIndex      = 0;
                if (found.Count() > 0)
                {
                    info      = found.First();
                    titles    = info.Tracks;
                    infoIndex = Array.IndexOf(info.AudioIds, dumpFile.Header.AudioId);
                    Array.Resize(ref info.Hash, info.AudioIds.Length);
                    infoHashString = info.Hash[infoIndex];

                    message.AppendLine("  Header: JSON Name   '" + info.Title + "'");
                }
                if (!string.IsNullOrEmpty(customName))
                {
                    message.AppendLine("  Header: Custom Name '" + customName + "'");
                }

                message.AppendLine("  Header: Length      0x" + dumpFile.HeaderLength.ToString("X8") + " " + ((dumpFile.HeaderLength != 0xFFC) ? " [WARNING: EXTRA DATA]" : "[OK]"));
                message.AppendLine("  Header: Padding     0x" + dumpFile.Header.Padding.Length.ToString("X8"));
                message.AppendLine("  Header: AudioLen    0x" + dumpFile.Header.AudioLength.ToString("X8") + " " + (dumpFile.Header.AudioLength == dumpFile.Audio.Length ? "[OK]" : "[INCORRECT]"));
                message.AppendLine("  Header: Checksum    " + hashString + " " + (dumpFile.HashCorrect ? "[OK]" : "[INCORRECT]") + " " + (infoHashString != null ? (infoHashString == hashString ? "[JSON MATCH]" : "[JSON MISMATCH]") : "[NO JSON INFO]"));
                message.AppendLine("  Header: Chapters    ");

                if (info != null && infoHashString == null)
                {
                    info.Hash[infoIndex] = hashString;
                }

                TimeSpan prevTime = new TimeSpan();
                for (int track = 1; track <= dumpFile.Header.AudioChapters.Length; track++)
                {
                    uint off = dumpFile.GetHighestPage();

                    if (track < dumpFile.Header.AudioChapters.Length)
                    {
                        off = dumpFile.Header.AudioChapters[track];
                    }
                    ulong  granule      = dumpFile.GetGranuleByPage(off);
                    string lengthString = "@" + off;

                    if (granule != ulong.MaxValue)
                    {
                        TimeSpan trackOffset = TimeSpan.FromSeconds(granule / 48000.0f);
                        lengthString = (trackOffset - prevTime).ToString(@"mm\:ss\.ff");
                        prevTime     = trackOffset;
                    }

                    string title = "";

                    if (titles != null && track - 1 < titles.Length)
                    {
                        title = titles[track - 1];
                    }
                    message.AppendLine("    Track #" + track.ToString("00") + "  " + lengthString + "  " + title);
                }

                message.AppendLine("  Ogg: Segments       " + segCount + " (min: " + minSegs + " max: " + maxSegs + " per OggPage)");
                message.AppendLine("  Ogg: net payload    " + segLength + " byte");
                message.AppendLine("  Ogg: granules       total: " + highestGranule + " (" + TonieAudio.FormatGranule(highestGranule) + " hh:mm:ss.ff)");
                message.AppendLine("  Ogg: granules/page  min: " + minGranule + " max: " + maxGranule + " (" + (1000 * minGranule / 48000.0f) + "ms - " + (1000 * maxGranule / 48000.0f) + "ms)");
                message.AppendLine();
                break;
            }

            case eDumpFormat.FormatJSON:
            {
                if (!first)
                {
                    message.AppendLine(",");
                }
                message.AppendLine("  {");
                message.AppendLine("    \"uid\": \"" + uid + "\",");
                message.AppendLine("    \"audio_id\": \"" + dumpFile.Header.AudioId.ToString("X8") + "\",");
                message.AppendLine("    \"audio_date\": \"" + date.ToString("yyyy'-'MM'-'dd'T'HH':'mm':'ss") + "\",");
                message.AppendLine("    \"header_length\": " + dumpFile.HeaderLength + ",");
                message.AppendLine("    \"header_ok\": \"" + ((dumpFile.HeaderLength != 0xFFC) ? "FALSE" : "TRUE") + "\",");
                message.AppendLine("    \"padding\": " + dumpFile.Header.Padding.Length + ",");
                message.AppendLine("    \"audio_length\": " + dumpFile.Header.AudioLength + ",");
                message.AppendLine("    \"audio_length_check\": \"" + (dumpFile.Header.AudioLength == dumpFile.Audio.Length ? "TRUE" : "FALSE") + "\",");
                message.AppendLine("    \"audio_hash\": \"" + BitConverter.ToString(dumpFile.Header.Hash).Replace("-", "") + "\",");
                message.AppendLine("    \"audio_hash_check\": \"" + (dumpFile.HashCorrect ? "TRUE" : "FALSE") + "\",");
                message.Append("    \"chapters\": [ 0");
                foreach (var offset in dumpFile.Header.AudioChapters)
                {
                    message.Append(", " + offset);
                }
                message.AppendLine(" ],");
                message.AppendLine("    \"segments\": " + segCount + ",");
                message.AppendLine("    \"min_segments_per_page\": " + minSegs + ",");
                message.AppendLine("    \"max_segments_per_page\": " + maxSegs + ",");
                message.AppendLine("    \"segment_length_sum\": " + segLength + ",");
                message.AppendLine("    \"highest_granule\": " + highestGranule + ",");
                message.AppendLine("    \"time\": \"" + TonieAudio.FormatGranule(highestGranule) + "\",");
                message.AppendLine("    \"min_granules\": " + minGranule + ",");
                message.AppendLine("    \"max_granules\": " + maxGranule + ",");
                message.AppendLine("    \"min_time\": " + (1000 * minGranule / 48000.0f) + ",");
                message.AppendLine("    \"max_time\": " + (1000 * maxGranule / 48000.0f) + "");
                message.AppendLine("  }");

                break;
            }
            }

            return(true);
        }