예제 #1
0
 /// <summary>
 /// Creates a new MSF file from an MSF header and PCM data.
 /// </summary>
 /// <param name="header">The header. Be sure to set appropriate values properly.</param>
 /// <param name="body">The raw 16-bit PCM data.</param>
 public unsafe MSF_PCM16LE(MSFHeader header, byte[] body) : base(header, body)
 {
     if (Header.codec != 1)
     {
         throw new FormatException("The codec of this MSF file is not little-endian 16-bit PCM");
     }
 }
예제 #2
0
        /// <summary>
        /// Reads an MSF file from a byte array.
        /// </summary>
        /// <param name="data">The complete data of the MSF file (including the header)</param>
        /// <returns>An MSF object</returns>
        public unsafe static MSF Parse(byte[] data)
        {
            fixed(byte *ptr = data)
            {
                MSFHeader header = *(MSFHeader *)ptr;
                int       size   = Math.Min(header.data_size, data.Length - sizeof(MSFHeader));

                byte[] body = new byte[size];
                Marshal.Copy((IntPtr)(ptr + sizeof(MSFHeader)), body, 0, body.Length);
                switch (header.codec)
                {
                case 0:
                    return(new MSF_PCM16BE(header, body));

                case 1:
                    return(new MSF_PCM16LE(header, body));

                case 7:
                    return(new MSF_MP3(header, body));

                default:
                    throw new NotSupportedException($"The codec {header.codec} is not supported.");
                }
            }
        }
예제 #3
0
 /// <summary>
 /// Creates a new MSF file from an MSF header and MP3 data.
 /// </summary>
 /// <param name="header">The header. Be sure to set the appropriate flags.</param>
 /// <param name="body">The MP3 data.</param>
 public MSF_MP3(MSFHeader header, byte[] body) : base(header, body)
 {
     if (Header.codec != 7)
     {
         throw new FormatException("The codec in the MSF header is not MP3");
     }
     SampleData = new Lazy <short[]>(() => Decode());
     Bitrate    = new Lazy <long>(() =>
     {
         double sampleCount      = SampleData.Value.Length / Header.channel_count;
         double seconds          = sampleCount / Header.sample_rate;
         double bytes_per_second = body.Length / seconds;
         return((long)Math.Round(bytes_per_second));
     });
 }
예제 #4
0
        public static unsafe MSFHeader Create()
        {
            MSFHeader h = new MSFHeader
            {
                tag   = MSFTag.Create(),
                flags = new MSFFlags {
                    Flags = MSFFlag.Resample
                }
            };

            for (int i = 0; i < 32; i++)
            {
                h.padding[i] = 0xFF;
            }
            return(h);
        }
예제 #5
0
 /// <summary>
 /// Creates a new MSF file from an MSF header and PCM data.
 /// </summary>
 /// <param name="header">The header. Be sure to set appropriate values properly.</param>
 /// <param name="body">The raw 16-bit PCM data.</param>
 public unsafe MSF_PCM16(MSFHeader header, byte[] body) : base(header, body)
 {
 }
예제 #6
0
 /// <summary>
 /// Creates a new MSF file.
 /// </summary>
 /// <param name="header">The header</param>
 /// <param name="body">The rest of the data</param>
 protected MSF(MSFHeader header, byte[] body)
 {
     _header = header;
     _body   = body;
 }
예제 #7
0
        /// <summary>
        /// Creates a new MSF (with a 16-bit PCM codec) using an IPCM16AudioSource object as the source.
        /// </summary>
        /// <param name="source">The IPCM16AudioSource object</param>
        /// <param name="big_endian">Whether to use big-endian (default is true)</param>
        /// <returns></returns>
        public unsafe static MSF FromAudioSource(IPcmAudioSource <short> source, bool big_endian = true)
        {
            short[] samples = source.SampleData.ToArray();

            MSFHeader header = MSFHeader.Create();

            header.codec         = big_endian ? 0 : 1;
            header.channel_count = source.Channels;
            header.data_size     = samples.Length * sizeof(short);
            header.sample_rate   = source.SampleRate;
            if (source.IsLooping)
            {
                header.flags.Flags |= MSFFlag.LoopMarker0;
            }

            MSF_PCM16 msf;

            if (big_endian)
            {
                BigEndianInt16[] samples_be = new BigEndianInt16[samples.Length];
                for (int i = 0; i < samples.Length; i++)
                {
                    samples_be[i] = samples[i];
                }
                byte[] data = new byte[samples.Length * sizeof(short)];
                fixed(BigEndianInt16 *ptr = samples_be)
                {
                    Marshal.Copy((IntPtr)ptr, data, 0, data.Length);
                }

                msf = new MSF_PCM16BE(header, data);
            }
            else
            {
                LittleEndianInt16[] samples_le = new LittleEndianInt16[samples.Length];
                for (int i = 0; i < samples.Length; i++)
                {
                    samples_le[i] = samples[i];
                }
                byte[] data = new byte[samples.Length * sizeof(short)];
                fixed(LittleEndianInt16 *ptr = samples_le)
                {
                    Marshal.Copy((IntPtr)ptr, data, 0, data.Length);
                }

                msf = new MSF_PCM16LE(header, data);
            }

            if (source.IsLooping)
            {
                msf.LoopStartSample = source.LoopStartSample;
                if (msf.LoopStartSample != source.LoopStartSample)
                {
                    throw new Exception();
                }
                msf.LoopSampleCount = source.LoopSampleCount;
                if (msf.LoopSampleCount != source.LoopSampleCount)
                {
                    throw new Exception();
                }
            }
            return(msf);
        }