音声データの中身を見たり変更したりする為のクラス
Пример #1
0
        /// <summary> 音声波形を生成する </summary>
        /// <param name="pronounce"> (株)アクエストが定める発音記号列 </param>
        /// <returns> wavファイルの内容物に相当するデータ </returns>
        public byte[] CreateWav(string pronounce)
        {
            try
            {
                int size = 0;

                IntPtr wavPtr = SyntheWave(pronounce, Speed, ref size);

                //wav生成に失敗してるケース: 具体的には[あ-んア-ン.,。、/+_]あたりの記号以外が入ってると失敗する
                if (wavPtr == IntPtr.Zero)
                {
                    //ヌルぽなので意味はないハズだが一応
                    FreeWave(wavPtr);
                    return(new byte[] { });
                }

                var wav = new byte[size];
                Marshal.Copy(wavPtr, wav, 0, size);

                FreeWave(wavPtr);

                //パラメタに応じて波形処理が入る
                //FIXME: NAudio使った方がカッコいい…か?AquesTalkだけターゲットにするなら別に現状でもいいが
                WaveInfo.ChangePitch(wav, Pitch);
                WaveInfo.ChangeVolume(wav, Volume);

                return(wav);
            }
            catch (ArgumentNullException)
            {
                return(new byte[] { });
            }
        }
Пример #2
0
        /// <summary>
        /// ピッチを変更する。読み上げ速度と声の高さが変わる
        /// CAUTION: AquesTalk以外の音声データに対応させてない
        /// </summary>
        /// <param name="wav">音声データ</param>
        /// <param name="pitch">ピッチ(100が基準値)</param>
        public static void ChangePitch(byte[] wav, int pitch)
        {
            var   wInfo = new WaveInfo(wav);
            float rate  = pitch / 100.0f;

            wInfo.BytePerSec   = (uint)(wInfo.BytePerSec * rate);
            wInfo.SamplingRate = (uint)(wInfo.SamplingRate * rate);
            wInfo.SetInfoTo(wav);
        }
Пример #3
0
        /// <summary>
        /// ファイルのある位置での音量を取得する
        /// </summary>
        /// <param name="t">時刻</param>
        /// <param name="wav">時刻の周辺幅</param>
        /// <param name="width">周辺値をとってくる時間幅(秒)</param>
        /// <returns>音量の2乗平均値</returns>
        private static double VolumeAt(byte[] wav, double t, double width)
        {
            //2015/5/23変更: 任意のブロックサイズやBit Per Sampleに対応出来るようにする
            var wInfo         = new WaveInfo(wav);
            int bytePerSample = wInfo.BitPerSample / 8;
            int min           = (int)(t * wInfo.BytePerSec);
            int max           = (int)((t + width) * wInfo.BytePerSec);

            min = Math.Max(min, 0);
            max = Math.Min(max, wav.Length - 44 - bytePerSample);

            //スタート位置のアレイをきちんとする
            min -= min % bytePerSample;
            max -= max % bytePerSample;

            //44はヘッダの長さ
            min += 44;
            max += 44;

            //無いと思うがtやwidthの設定に対してロバストにしておく
            if (min >= max)
            {
                return(0.0);
            }

            var volumes = new float[(max - min) / bytePerSample];

            int index = 0;

            for (int i = min; i < max; i += bytePerSample)
            {
                //HACK: BigEndian対応のためbyte数毎に対応する。
                //いやホントは一般化できる(最上位ビット見て余剰ビット埋めればいい)んだけど…
                if (bytePerSample == 1)
                {
                    volumes[index] = wav[i] / 128.0f;
                }
                else if (bytePerSample == 2)
                {
                    volumes[index] = GetShortFrom(wav[i], wav[i + 1]) / 32768.0f;
                }
                else if (bytePerSample == 3)
                {
                    var wavValue = new byte[3];
                    Array.Copy(wav, i, wavValue, 0, 3);
                    volumes[index] = GetIntFrom3Byte(wavValue) / 8388608.0f;
                }
                index++;
            }

            return(Math.Sqrt(volumes.Sum(v => v * v) / volumes.Length));
        }
Пример #4
0
        /// <summary>
        /// wavを時間でぶつ切りにして音量の配列を返す。口パク連動サポート。
        /// </summary>
        /// <param name="wav">音声データ(.wav)</param>
        /// <param name="interval">時間区切り幅</param>
        /// <returns></returns>
        private static double[] Volumes(byte[] wav, double interval)
        {
            var wInfo  = new WaveInfo(wav);
            var result = new List <double>();

            for (int i = 1; (i + 1) * interval < wInfo.PlayTime; i++)
            {
                result.Add(VolumeAt(wav, i * interval, interval));
            }

            //
            //File.WriteAllLines("wavMeans.dat", result.Select(v => v.ToString()).ToArray());

            return(result.ToArray());
        }
Пример #5
0
 /// <summary>
 /// ピッチを変更する。読み上げ速度と声の高さが変わる
 /// CAUTION: AquesTalk以外の音声データに対応させてない
 /// </summary>
 /// <param name="wav">音声データ</param>
 /// <param name="pitch">ピッチ(100が基準値)</param>
 public static void ChangePitch(byte[] wav, int pitch)
 {
     var wInfo = new WaveInfo(wav);
     float rate = pitch / 100.0f;
     wInfo.BytePerSec = (uint)(wInfo.BytePerSec * rate);
     wInfo.SamplingRate = (uint)(wInfo.SamplingRate * rate);
     wInfo.SetInfoTo(wav);
 }
Пример #6
0
        /// <summary>
        /// ファイルのある位置での音量を取得する
        /// </summary>
        /// <param name="t">時刻</param>
        /// <param name="wav">時刻の周辺幅</param>
        /// <param name="width">周辺値をとってくる時間幅(秒)</param>
        /// <returns>音量の2乗平均値</returns>
        private static double VolumeAt(byte[] wav, double t, double width)
        {
            //2015/5/23変更: 任意のブロックサイズやBit Per Sampleに対応出来るようにする
            var wInfo = new WaveInfo(wav);
            int bytePerSample = wInfo.BitPerSample / 8;
            int min = (int)(t * wInfo.BytePerSec);
            int max = (int)((t + width) * wInfo.BytePerSec);

            min = Math.Max(min, 0);
            max = Math.Min(max, wav.Length - 44 - bytePerSample);

            //スタート位置のアレイをきちんとする
            min -= min % bytePerSample;
            max -= max % bytePerSample;

            //44はヘッダの長さ
            min += 44;
            max += 44;

            //無いと思うがtやwidthの設定に対してロバストにしておく
            if (min >= max) return 0.0;

            var volumes = new float[(max - min) / bytePerSample];

            int index = 0;
            for (int i = min; i < max; i += bytePerSample)
            {
                //HACK: BigEndian対応のためbyte数毎に対応する。
                //いやホントは一般化できる(最上位ビット見て余剰ビット埋めればいい)んだけど…
                if (bytePerSample == 1)
                {
                    volumes[index] = wav[i] / 128.0f;
                }
                else if (bytePerSample == 2)
                {
                    volumes[index] = GetShortFrom(wav[i], wav[i + 1]) / 32768.0f;
                }
                else if (bytePerSample == 3)
                {
                    var wavValue = new byte[3];
                    Array.Copy(wav, i, wavValue, 0, 3);
                    volumes[index] = GetIntFrom3Byte(wavValue) / 8388608.0f;
                }
                index++;
            }

            return Math.Sqrt(volumes.Sum(v => v * v) / volumes.Length);

        }
Пример #7
0
        /// <summary>
        /// wavを時間でぶつ切りにして音量の配列を返す。口パク連動サポート。
        /// </summary>
        /// <param name="wav">音声データ(.wav)</param>
        /// <param name="interval">時間区切り幅</param>
        /// <returns></returns>
        private static double[] Volumes(byte[] wav, double interval)
        {
            var wInfo = new WaveInfo(wav);
            var result = new List<double>();

            for (int i = 1; (i + 1) * interval < wInfo.PlayTime; i++)
            {
                result.Add(VolumeAt(wav, i * interval, interval));
            }

            //
            //File.WriteAllLines("wavMeans.dat", result.Select(v => v.ToString()).ToArray());

            return result.ToArray();
        }