/// <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"); } }
/// <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."); } } }
/// <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)); }); }
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); }
/// <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) { }
/// <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; }
/// <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); }