OSDN Git Service

#40868 CPrivateFont()の機能強化。
[dtxmania/dtxmania.git] / NVorbis / VorbisReader.cs
1 /****************************************************************************
2  * NVorbis                                                                  *
3  * Copyright (C) 2014, Andrew Ward <afward@gmail.com>                       *
4  *                                                                          *
5  * See COPYING for license terms (Ms-PL).                                   *
6  *                                                                          *
7  ***************************************************************************/
8 using System;
9 using System.Collections.Generic;
10 using System.Linq;
11 using System.Text;
12 using System.IO;
13 using System.Diagnostics;
14
15 namespace NVorbis
16 {
17     public class VorbisReader : IDisposable
18     {
19         int _streamIdx;
20
21         IContainerReader _containerReader;
22         List<VorbisStreamDecoder> _decoders;
23         List<int> _serials;
24
25         VorbisReader()
26         {
27             ClipSamples = true;
28
29             _decoders = new List<VorbisStreamDecoder>();
30             _serials = new List<int>();
31
32         }
33
34         public VorbisReader(string fileName)
35             : this(File.Open(fileName, FileMode.Open, FileAccess.Read, FileShare.Read), true)
36         {
37         }
38
39         public VorbisReader(Stream stream, bool closeStreamOnDispose)
40             : this()
41         {
42             var bufferedStream = new BufferedReadStream(stream);
43             bufferedStream.CloseBaseStream = closeStreamOnDispose;
44
45                         // try Ogg first
46                         var oggContainer = new Ogg.ContainerReader(bufferedStream, closeStreamOnDispose);
47             if (!LoadContainer(oggContainer))
48             {
49                // oops, not Ogg!
50                 // we don't support any other container types yet, so error out
51                 // TODO: Add Matroska fallback
52                 bufferedStream.Close();
53                 throw new InvalidDataException("Could not determine container type!!");
54             }
55            _containerReader = oggContainer;
56
57             if (_decoders.Count == 0) throw new InvalidDataException("No Vorbis data found!");
58         }
59
60         public VorbisReader(IContainerReader containerReader)
61             : this()
62         {
63             if (!LoadContainer(containerReader))
64             {
65                 throw new InvalidDataException("Container did not initialize!");
66             }
67             _containerReader = containerReader;
68
69             if (_decoders.Count == 0) throw new InvalidDataException("No Vorbis data found!");
70         }
71
72         public VorbisReader(IPacketProvider packetProvider)
73             : this()
74         {
75             var ea = new NewStreamEventArgs(packetProvider);
76             NewStream(this, ea);
77             if (ea.IgnoreStream) throw new InvalidDataException("No Vorbis data found!");
78         }
79
80         bool LoadContainer(IContainerReader containerReader)
81         {
82             containerReader.NewStream += NewStream;
83             if (!containerReader.Init())
84             {
85                 containerReader.NewStream -= NewStream;
86                 return false;
87             }
88             return true;
89         }
90
91         void NewStream(object sender, NewStreamEventArgs ea)
92         {
93             var packetProvider = ea.PacketProvider;
94             var decoder = new VorbisStreamDecoder(packetProvider);
95             if (decoder.TryInit())
96             {
97                 _decoders.Add(decoder);
98                 _serials.Add(packetProvider.StreamSerial);
99             }
100             else
101             {
102                 // This is almost certainly not a Vorbis stream
103                 ea.IgnoreStream = true;
104             }
105         }
106
107         public void Dispose()
108         {
109             if (_decoders != null)
110             {
111                 foreach (var decoder in _decoders)
112                 {
113                     decoder.Dispose();
114                 }
115                 _decoders.Clear();
116                 _decoders = null;
117             }
118
119             if (_containerReader != null)
120             {
121                 _containerReader.NewStream -= NewStream;
122                 _containerReader.Dispose();
123                 _containerReader = null;
124             }
125         }
126
127         VorbisStreamDecoder ActiveDecoder
128         {
129             get
130             {
131                 if (_decoders == null) throw new ObjectDisposedException("VorbisReader");
132                 return _decoders[_streamIdx];
133             }
134         }
135
136         #region Public Interface
137
138         /// <summary>
139         /// Gets the number of channels in the current selected Vorbis stream
140         /// </summary>
141         public int Channels { get { return ActiveDecoder._channels; } }
142
143         /// <summary>
144         /// Gets the sample rate of the current selected Vorbis stream
145         /// </summary>
146         public int SampleRate { get { return ActiveDecoder._sampleRate; } }
147
148         /// <summary>
149         /// Gets the encoder's upper bitrate of the current selected Vorbis stream
150         /// </summary>
151         public int UpperBitrate { get { return ActiveDecoder._upperBitrate; } }
152
153         /// <summary>
154         /// Gets the encoder's nominal bitrate of the current selected Vorbis stream
155         /// </summary>
156         public int NominalBitrate { get { return ActiveDecoder._nominalBitrate; } }
157
158         /// <summary>
159         /// Gets the encoder's lower bitrate of the current selected Vorbis stream
160         /// </summary>
161         public int LowerBitrate { get { return ActiveDecoder._lowerBitrate; } }
162
163         /// <summary>
164         /// Gets the encoder's vendor string for the current selected Vorbis stream
165         /// </summary>
166         public string Vendor { get { return ActiveDecoder._vendor; } }
167
168         /// <summary>
169         /// Gets the comments in the current selected Vorbis stream
170         /// </summary>
171         public string[] Comments { get { return ActiveDecoder._comments; } }
172
173         /// <summary>
174         /// Gets whether the previous short sample count was due to a parameter change in the stream.
175         /// </summary>
176         public bool IsParameterChange { get { return ActiveDecoder.IsParameterChange; } }
177
178         /// <summary>
179         /// Gets the number of bits read that are related to framing and transport alone
180         /// </summary>
181         public long ContainerOverheadBits { get { return ActiveDecoder.ContainerBits; } }
182
183         /// <summary>
184         /// Gets or sets whether to automatically apply clipping to samples returned by <see cref="VorbisReader.ReadSamples"/>.
185         /// </summary>
186         public bool ClipSamples { get; set; }
187
188         /// <summary>
189         /// Gets stats from each decoder stream available
190         /// </summary>
191         public IVorbisStreamStatus[] Stats
192         {
193             get { return _decoders.Select(d => d).Cast<IVorbisStreamStatus>().ToArray(); }
194         }
195
196         /// <summary>
197         /// Gets the currently-selected stream's index
198         /// </summary>
199         public int StreamIndex
200         {
201             get { return _streamIdx; }
202         }
203
204         /// <summary>
205         /// Reads decoded samples from the current logical stream
206         /// </summary>
207         /// <param name="buffer">The buffer to write the samples to</param>
208         /// <param name="offset">The offset into the buffer to write the samples to</param>
209         /// <param name="count">The number of samples to write</param>
210         /// <returns>The number of samples written</returns>
211         public int ReadSamples(float[] buffer, int offset, int count)
212         {
213             if (offset < 0) throw new ArgumentOutOfRangeException("offset");
214             if (count < 0 || offset + count > buffer.Length) throw new ArgumentOutOfRangeException("count");
215
216             count = ActiveDecoder.ReadSamples(buffer, offset, count);
217
218             if (ClipSamples)
219             {
220                 var decoder = _decoders[_streamIdx];
221                 for (int i = 0; i < count; i++, offset++)
222                 {
223                     buffer[offset] = Utils.ClipValue(buffer[offset], ref decoder._clipped);
224                 }
225             }
226
227             return count;
228         }
229
230         /// <summary>
231         /// Clears the parameter change flag so further samples can be requested.
232         /// </summary>
233         public void ClearParameterChange()
234         {
235             ActiveDecoder.IsParameterChange = false;
236         }
237
238         /// <summary>
239         /// Returns the number of logical streams found so far in the physical container
240         /// </summary>
241         public int StreamCount
242         {
243             get { return _decoders.Count; }
244         }
245
246         /// <summary>
247         /// Searches for the next stream in a concatenated file
248         /// </summary>
249         /// <returns><c>True</c> if a new stream was found, otherwise <c>false</c>.</returns>
250         public bool FindNextStream()
251         {
252             if (_containerReader == null) return false;
253             return _containerReader.FindNextStream();
254         }
255
256         /// <summary>
257         /// Switches to an alternate logical stream.
258         /// </summary>
259         /// <param name="index">The logical stream index to switch to</param>
260         /// <returns><c>True</c> if the properties of the logical stream differ from those of the one previously being decoded. Otherwise, <c>False</c>.</returns>
261         public bool SwitchStreams(int index)
262         {
263             if (index < 0 || index >= StreamCount) throw new ArgumentOutOfRangeException("index");
264
265             if (_decoders == null) throw new ObjectDisposedException("VorbisReader");
266
267             if (_streamIdx == index) return false;
268
269             var curDecoder = _decoders[_streamIdx];
270             _streamIdx = index;
271             var newDecoder = _decoders[_streamIdx];
272
273             return curDecoder._channels != newDecoder._channels || curDecoder._sampleRate != newDecoder._sampleRate;
274         }
275
276         /// <summary>
277         /// Gets or Sets the current timestamp of the decoder.  Is the timestamp before the next sample to be decoded
278         /// </summary>
279         public TimeSpan DecodedTime
280         {
281             get
282             {
283                 return TimeSpan.FromSeconds((double)ActiveDecoder.CurrentPosition / SampleRate);
284             }
285             set
286             {
287                 ActiveDecoder.SeekTo((long)(value.TotalSeconds * SampleRate));
288             }
289
290         }
291
292         /// <summary>
293         /// Gets or Sets the current position of the next sample to be decoded.
294         /// </summary>
295         public long DecodedPosition
296         {
297             get 
298             {
299                 return ActiveDecoder.CurrentPosition;
300             }
301             set
302             {
303                 ActiveDecoder.SeekTo(value);
304             }
305         }
306
307         /// <summary>
308         /// Gets the total length of the current logical stream
309         /// </summary>
310         public TimeSpan TotalTime
311         {
312             get
313             {
314                 var decoder = ActiveDecoder;
315                 if (decoder.CanSeek)
316                 {
317                     return TimeSpan.FromSeconds((double)decoder.GetLastGranulePos() / decoder._sampleRate);
318                 }
319                 else
320                 {
321                     return TimeSpan.MaxValue;
322                 }
323             }
324         }
325
326         public long TotalSamples
327         {
328             get
329             {
330                 var decoder = ActiveDecoder;
331                 if (decoder.CanSeek)
332                 {
333                     return decoder.GetLastGranulePos();
334                 }
335                 else
336                 {
337                     return long.MaxValue;
338                 }
339             }
340         }
341         
342         #endregion
343     }
344 }