예제 #1
0
    private AudioClip ParseWAV(string clipName, byte[] data)
    {
        MemoryStream stream = new MemoryStream(data, false);
        BinaryReader reader = new BinaryReader(stream);

        IFF_FORM_CHUNK form = ReadType <IFF_FORM_CHUNK>(reader);

        if (GetID(form.form_id) != "RIFF" || GetID(form.id) != "WAVE")
        {
            _lastError = String.Format("Malformed WAV header: {0} != RIFF || {1} != WAVE", GetID(form.form_id), GetID(form.id));
            return(null);
        }

        WAV_PCM header       = new WAV_PCM();
        bool    bHeaderFound = false;

        while (reader.BaseStream.Position < reader.BaseStream.Length)
        {
            IFF_CHUNK chunk = ReadType <IFF_CHUNK>(reader);

            int ChunkLength = (int)chunk.length;
            if (ChunkLength < 0)  // HACK: Deal with TextToSpeech bug where the chunk length is not set for the data chunk..
            {
                ChunkLength = (int)(reader.BaseStream.Length - reader.BaseStream.Position);
            }
            if ((ChunkLength & 0x1) != 0)
            {
                ChunkLength += 1;
            }

            long ChunkEnd = reader.BaseStream.Position + ChunkLength;
            if (GetID(chunk.id) == "fmt ")
            {
                bHeaderFound = true;
                header       = ReadType <WAV_PCM>(reader);
            }
            else if (GetID(chunk.id) == "data")
            {
                if (!bHeaderFound)
                {
                    _lastError = "Failed to find header.";
                    return(null);
                }
                byte[] waveform = reader.ReadBytes(ChunkLength);

                // convert into a float based wave form..
                int   channels = (int)header.channels;
                int   bps      = (int)header.bits_per_sample;
                float divisor  = 1 << (bps - 1);
                int   bytesps  = bps / 8;
                int   samples  = waveform.Length / bytesps;

                _lastError = string.Format("WAV INFO, channels = {0}, bps = {1}, samples = {2}, rate = {3}",
                                           channels, bps, samples, header.sample_rate);

                float[] wf = new float[samples];
                if (bps == 16)
                {
                    for (int s = 0; s < samples; ++s)
                    {
                        wf[s] = ((float)BitConverter.ToInt16(waveform, s * bytesps)) / divisor;
                    }
                }
                else if (bps == 32)
                {
                    for (int s = 0; s < samples; ++s)
                    {
                        wf[s] = ((float)BitConverter.ToInt32(waveform, s * bytesps)) / divisor;
                    }
                }
                else if (bps == 8)
                {
                    for (int s = 0; s < samples; ++s)
                    {
                        wf[s] = ((float)BitConverter.ToChar(waveform, s * bytesps)) / divisor;
                    }
                }
                else
                {
                    _lastError = string.Format("Unspported BPS {0} in WAV data.", bps.ToString());
                    return(null);
                }

                AudioClip clip = AudioClip.Create(clipName, samples, channels, (int)header.sample_rate, false);
                clip.SetData(wf, 0);

                return(clip);
            }

            reader.BaseStream.Position = ChunkEnd;
        }

        return(null);
    }
예제 #2
0
        /// <summary>
        /// Creates a WAV file from a AudioClip object.
        /// </summary>
        /// <param name="clip">The AudioClip object to generate the WAV file from.</param>
        /// <param name="bps">How many bits per sample we should use in the WAV file, 8, 16, or 32.</param>
        /// <returns>Returns a byte array of the raw data of the WAV file.</returns>
        public static byte[] CreateWAV(AudioClip clip, int bps = 16)
        {
            MemoryStream stream = new MemoryStream();
            BinaryWriter writer = new BinaryWriter(stream);

            IFF_FORM_CHUNK form = new IFF_FORM_CHUNK();

            form.form_id     = MakeID("RIFF");
            form.form_length = 0xffffffff;
            form.id          = MakeID("WAVE");
            WriteType(writer, form);

            long  form_start = writer.BaseStream.Position;
            float divisor    = 1 << (bps - 1);

            WAV_PCM header = new WAV_PCM();

            header.format_tag        = 1;
            header.alignment         = 2;
            header.bits_per_sample   = (ushort)bps;
            header.sample_rate       = (uint)clip.frequency;
            header.channels          = (ushort)clip.channels;
            header.average_data_rate = (uint)((bps / 8) * clip.channels * clip.frequency);

            IFF_CHUNK fmt = new IFF_CHUNK();

            fmt.id     = MakeID("fmt ");
            fmt.length = (uint)Marshal.SizeOf(header);
            WriteType(writer, fmt);
            WriteType(writer, header);

            IFF_CHUNK data = new IFF_CHUNK();

            data.id     = MakeID("data");
            data.length = (uint)((bps / 8) * clip.samples * clip.channels);
            WriteType(writer, data);

            float[] samples = new float[clip.samples * clip.channels];
            clip.GetData(samples, 0);

            if (bps == 16)
            {
                for (int i = 0; i < samples.Length; ++i)
                {
                    writer.Write((short)(samples[i] * divisor));
                }
            }
            else if (bps == 32)
            {
                for (int i = 0; i < samples.Length; ++i)
                {
                    writer.Write((int)(samples[i] * divisor));
                }
            }
            else if (bps == 8)
            {
                for (int i = 0; i < samples.Length; ++i)
                {
                    writer.Write((char)(samples[i] * divisor));
                }
            }
            else
            {
                Log.Error("WaveFile.CreateWAV()", "Unsupported BPS {0} in WAV data.", bps.ToString());
                return(null);
            }

            // lastly, update the form length..
            form.form_length = (uint)(writer.BaseStream.Position - form_start);
            writer.Seek(0, SeekOrigin.Begin);
            WriteType(writer, form);

#if NETFX_CORE
            ArraySegment <byte> bytes;
            if (stream.TryGetBuffer(out bytes))
            {
                return(bytes.Array);
            }
            else
            {
                return(null);
            }
#else
            return(stream.GetBuffer());
#endif
        }