OSDN Git Service

Array.Copy() を Buffer.BlockCopy() に変更。
[strokestylet/CsWin10Desktop3.git] / FDK / メディア / サウンド / WASAPI / NVorbisResampledWaveSource.cs
1 using System;
2 using System.Collections.Generic;
3 using System.Diagnostics;
4 using System.IO;
5 using System.Linq;
6 using CSCore;
7 using CSCore.DSP;
8 using NVorbis;
9
10 namespace FDK.メディア.サウンド.WASAPI
11 {
12         /// <summary>
13         ///             指定されたメディアファイル(動画, 音楽)を Vorbis としてデコードして、CSCore.IWaveSource オブジェクトを生成する。
14         ///             リサンプラーあり版。
15         /// </summary>
16         public class NVorbisResampledWaveSource : IWaveSource
17         {
18                 public bool CanSeek => true;    // オンメモリなので常にサポートできる。
19
20                 /// <summary>
21                 ///             デコード&リサンプル後のオーディオデータのフォーマット。
22                 /// </summary>
23                 public WaveFormat WaveFormat
24                 {
25                         get;
26                         protected set;
27                 } = null;
28
29                 /// <summary>
30                 ///             デコード後のオーディオデータのすべての長さ[byte]。
31                 /// </summary>
32                 public long Length
33                         => this._EncodedWaveData.Length;
34
35                 /// <summary>
36                 ///             現在の再生位置[byte]。
37                 /// </summary>
38                 public long Position
39                 {
40                         get
41                                 => this._Position;
42                         set
43                                 => this._Position = FDKUtilities.位置をブロック境界単位にそろえて返す( value, this.WaveFormat.BlockAlign );
44                 }
45
46
47                 /// <summary>
48                 ///             コンストラクタ。
49                 ///             指定されたVorbisファイルを指定されたフォーマットでデコードし、内部にオンメモリで保管する。
50                 /// </summary>
51                 public NVorbisResampledWaveSource( Stream stream, WaveFormat deviceFormat )
52                 {
53                         this.WaveFormat = new WaveFormat(
54                                 deviceFormat.SampleRate,
55                                 32,
56                                 deviceFormat.Channels,
57                                 AudioEncoding.IeeeFloat );
58
59                         // リサンプルなし版で生成して、それを this.WaveFormat に合わせてリサンプルしたデータ(byte[])を保管する。
60                         using( var vorbisSource = new NVorbisSampleSource( stream, deviceFormat ) )
61                         using( var resampler = new DmoResampler( vorbisSource.ToWaveSource(), this.WaveFormat ) )
62                         {
63                                 // resampler.Length はサンプル単位ではなくフレーム単位。
64                                 var サイズbyte = resampler.Length * resampler.WaveFormat.Channels; // 実際のサイズはチャンネル倍ある。
65
66                                 this._EncodedWaveData = new byte[ サイズbyte ];
67                                 resampler.Read( this._EncodedWaveData, 0, (int) サイズbyte );        // でもこっちはバイト単位。
68                         }
69                 }
70
71                 /// <summary>
72                 ///             連続したデータを読み込み、<see cref="Position"/> を読み込んだ数だけ進める。
73                 /// </summary>
74                 /// <param name="buffer">読み込んだデータを格納するための配列。</param>
75                 /// <param name="offset"><paramref name="buffer"/> に格納を始める位置。</param>
76                 /// <param name="count">読み込む最大のデータ数。</param>
77                 /// <returns><paramref name="buffer"/> に読み込んだデータの総数。</returns>
78                 public int Read( byte[] buffer, int offset, int count )
79                 {
80                         // ※ 音がめちゃくちゃになるとうざいので、このメソッド内では例外を出さないこと。
81                         if( ( null == this._EncodedWaveData ) || ( null == buffer ) )
82                                 return 0;
83
84                         long 読み込み可能な最大count = ( this.Length - this._Position );
85                         if( count > 読み込み可能な最大count )
86                                 count = (int) 読み込み可能な最大count;
87
88                         if( 0 < count )
89                         {
90                                 Buffer.BlockCopy(
91                                         src: this._EncodedWaveData,
92                                         srcOffset: (int) this._Position,
93                                         dst: buffer,
94                                         dstOffset: offset,
95                                         count: count );
96
97                                 this._Position += count;
98                         }
99
100                         return count;
101                 }
102
103                 /// <summary>
104                 ///             解放する。
105                 /// </summary>
106                 public void Dispose()
107                 {
108                         this._EncodedWaveData = null;
109                 }
110
111                 private byte[] _EncodedWaveData = null;
112                 private long _Position = 0;
113         }
114 }