Changeset 1154


Ignore:
Timestamp:
May 3, 2021, 5:22:15 PM (4 years ago)
Author:
geyser
Message:

Implemented import/export of "fact" chunk for .wav files. Added a -demo tag for storing sounds in the PC demo format (if compatible).

Location:
OniSplit
Files:
4 edited

Legend:

Unmodified
Added
Removed
  • OniSplit/Program.cs

    r1132 r1154  
    844844                case ".wav":
    845845                    if (task.Type == TemplateTag.NONE || task.Type == TemplateTag.SNDD)
    846                         importer = new WavImporter();
     846                        importer = new WavImporter(args.Any(a => a == "-demo"));
    847847                    break;
    848848
  • OniSplit/Sound/WavExporter.cs

    r1131 r1154  
    154154            using (var writer = new BinaryWriter(stream))
    155155            {
    156                 var blockSizeADPCM = 512 * sound.ChannelCount * sound.SampleRate / 22050;
     156                var blockSizeADPCM = sound.BlockAlignment;
     157               
    157158                int wholeBlocks = sound.Data.Length / blockSizeADPCM;
    158159                int leftoverBytes = sound.Data.Length - (wholeBlocks * blockSizeADPCM);
    159                 int leftoverSamples = 8 * (leftoverBytes - 7 * sound.ChannelCount)
    160                                       / 4 / sound.ChannelCount + 2; // 4 bits per sample
     160                int leftoverSamples = 0;
     161                if(leftoverBytes > 14)
     162                    leftoverSamples = 2 + (leftoverBytes - 7 * sound.ChannelCount)
     163                                    * 8 / sound.BitsPerSample / sound.ChannelCount;
    161164                int paddingBytes = 0;
    162165                if (leftoverBytes > 0) // incomplete trailing block
    163166                    paddingBytes = blockSizeADPCM - leftoverBytes;
    164                 var samplesPerBlock = 2 + (blockSizeADPCM - sound.ChannelCount * 7) * 8 / sound.ChannelCount / 4;
    165 
    166                 Int32 sampleCount = sampleCount = wholeBlocks * samplesPerBlock + leftoverSamples;
     167                var samplesPerBlock = 2 + (blockSizeADPCM - sound.ChannelCount * 7) * 8 / sound.ChannelCount / sound.BitsPerSample;
     168
     169                Int32 sampleCount = wholeBlocks * samplesPerBlock + leftoverSamples;
    167170
    168171                if (sound.IsIMA4) // IMA4 ADPCM format
  • OniSplit/Sound/WavFile.cs

    r1114 r1154  
    22using System.Collections.Generic;
    33using System.IO;
     4//using System.Runtime.Remoting.Metadata.W3cXsd2001;
    45
    56namespace Oni.Sound
     
    1011        private const int fcc_RIFF = 0x46464952;
    1112        private const int fcc_WAVE = 0x45564157;
    12         private const int fcc_fmt = 0x20746d66;
     13        private const int fcc_fmt  = 0x20746d66;
     14        private const int fcc_fact = 0x74636166;
    1315        private const int fcc_data = 0x61746164;
    1416
     
    1921        private int blockAlign;
    2022        private int bitsPerSample;
     23        private int sampleCount;
    2124        private byte[] extraData;
    2225        private byte[] soundData;
     
    3538                    throw new InvalidDataException("Not a WAV file");
    3639
    37                 var header = new WavFile();
     40                var header = new WavFile()
     41                {
     42                    sampleCount = 0
     43                };
    3844
    3945                for (int chunkType, chunkSize, chunkStart; reader.Position < size; reader.Position = chunkStart + chunkSize)
     
    4551                    if (chunkType == fcc_fmt)
    4652                        header.ReadFormatChunk(reader, chunkSize);
    47                     else if (chunkType == fcc_data)
     53                    if (chunkType == fcc_fact)
     54                        header.ReadFactChunk(reader, chunkSize);
     55                    if (chunkType == fcc_data)
    4856                        header.ReadDataChunk(reader, chunkSize);
    4957                }
    5058
     59                header.ValidateSampleCount();
    5160                return header;
    5261            }
     
    6877        }
    6978
     79        private void ReadFactChunk(BinaryReader reader, int chunkSize)
     80        {
     81            sampleCount = reader.ReadInt32();
     82        }
     83
    7084        private void ReadDataChunk(BinaryReader reader, int chunkSize)
    7185        {
    7286            soundData = reader.ReadBytes(chunkSize);
     87        }
     88        private void ValidateSampleCount() // TODO: ACTUAL VALIDATION/CORRECTION
     89        {
     90            int sampleCountFromData = 0;
     91            int wholeBlocks = soundData.Length / blockAlign;
     92            if(sampleCount == 0) // not explicitly set (no fact chunk present)
     93            {
     94                Console.WriteLine("The imported WAV file has no FACT chunk.");
     95            }
     96            else // TODO: calculate sampleCountFromData, compare with sampleCount
     97            {
     98
     99            }
    73100        }
    74101
  • OniSplit/Sound/WavImporter.cs

    r1114 r1154  
    66    internal class WavImporter : Importer
    77    {
     8        private readonly bool convertToDemo;
     9
     10        public WavImporter(bool toDemo)
     11            : base(toDemo?InstanceFileHeader.OniMacTemplateChecksum:InstanceFileHeader.OniPCTemplateChecksum)
     12        {
     13            convertToDemo = toDemo;
     14        }
     15
    816        public override void Import(string filePath, string outputDirPath)
    917        {
     
    4452
    4553            var sndd = CreateInstance(TemplateTag.SNDD, name);
     54            if (convertToDemo)
     55            {
     56                // TODO: also validate other ADPCM parameters (coefficient table)?
     57                if (wav.Format != WavFormat.Adpcm) // Or is PCM supported, actually?
     58                    Console.WriteLine("Cannot convert to PC demo: ADPCM format required!");
     59                if (wav.SampleRate != 22050)
     60                    Console.WriteLine("Cannot convert to PC demo: 22050 kHz required!");
     61                if (wav.BlockAlign != 512 * wav.ChannelCount)
     62                    Console.WriteLine("Cannot convert to PC demo: wrong block alignment!");
     63                if (wav.BitsPerSample != 4)
     64                    Console.WriteLine("Cannot convert to PC demo: wrong bits per sample!");
    4665
    47             using (var writer = sndd.OpenWrite(8))
     66                using (var writer = sndd.OpenWrite())
     67                {
     68                    if (wav.ChannelCount == 2)
     69                        writer.WriteInt16(3);
     70                    else
     71                        writer.WriteInt16(1);
     72                    writer.WriteInt16(0);
     73                    writer.Write((int)duration);
     74                    writer.Write(wav.SoundData.Length);
     75                    writer.Write(WriteRawPart(wav.SoundData));
     76                }
     77            }
     78            else
    4879            {
    49                 writer.Write((short)wav.Format);
    50                 writer.WriteInt16(wav.ChannelCount);
    51                 writer.Write(wav.SampleRate);
    52                 writer.Write(wav.AverageBytesPerSecond);
    53                 writer.WriteInt16(wav.BlockAlign);
    54                 writer.WriteInt16(wav.BitsPerSample);
    55                 writer.WriteInt16(wav.ExtraData.Length);
    56                 writer.Write(wav.ExtraData);
    57                 writer.Skip(32 - wav.ExtraData.Length);
    58                 writer.Write((short)duration);
    59                 writer.Write(wav.SoundData.Length);
    60                 writer.Write(WriteRawPart(wav.SoundData));
     80                using (var writer = sndd.OpenWrite())
     81                {
     82                    if (wav.Format == WavFormat.Adpcm)
     83                        writer.WriteInt16(8);
     84                    else
     85                        writer.WriteInt16(0);
     86                    writer.WriteInt16(0);
     87                    writer.Write((short)wav.Format);
     88                    writer.WriteInt16(wav.ChannelCount);
     89                    writer.Write(wav.SampleRate);
     90                    writer.Write(wav.AverageBytesPerSecond);
     91                    writer.WriteInt16(wav.BlockAlign);
     92                    writer.WriteInt16(wav.BitsPerSample);
     93                    writer.WriteInt16(wav.ExtraData.Length);
     94                    writer.Write(wav.ExtraData);
     95                    writer.Skip(32 - wav.ExtraData.Length);
     96                    writer.Write((short)duration);
     97                    writer.Write(wav.SoundData.Length);
     98                    writer.Write(WriteRawPart(wav.SoundData));
     99                }
    61100            }
    62101        }
Note: See TracChangeset for help on using the changeset viewer.