added audio resource format.

This commit is contained in:
morkt 2014-11-07 02:44:22 +04:00
parent 0164ce838a
commit 07ea1b9af7
4 changed files with 331 additions and 0 deletions

167
GameRes/Audio.cs Normal file
View File

@ -0,0 +1,167 @@
//! \file Audio.cs
//! \date Tue Nov 04 17:35:54 2014
//! \brief audio format class.
//
// Copyright (C) 2014 by morkt
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//
using System.IO;
namespace GameRes
{
public struct WaveFormat
{
public ushort FormatTag;
public ushort Channels;
public uint SamplesPerSecond;
public uint AverageBytesPerSecond;
public ushort BlockAlign;
public ushort BitsPerSample;
}
public abstract class SoundInput : Stream
{
protected Stream m_input;
protected long m_pcm_size;
public override bool CanRead { get { return m_input.CanRead; } }
public override bool CanWrite { get { return false; } }
public override long Length { get { return m_pcm_size; } }
public long PcmSize
{
get { return m_pcm_size; }
protected set { m_pcm_size = value; }
}
public abstract int SourceBitrate { get; }
public WaveFormat Format { get; protected set; }
protected SoundInput (Stream input)
{
m_input = input;
}
public virtual void Reset ()
{
Position = 0;
}
#region System.IO.Stream methods
public override void Flush()
{
m_input.Flush();
}
public override long Seek(long offset, SeekOrigin origin)
{
if (origin == SeekOrigin.Begin)
Position = offset;
else if (origin == SeekOrigin.Current)
Position += offset;
else
Position = Length + offset;
return Position;
}
public override void SetLength (long length)
{
throw new System.NotSupportedException ("SoundInput.SetLength method is not supported");
}
public override void Write (byte[] buffer, int offset, int count)
{
throw new System.NotSupportedException ("SoundInput.Write method is not supported");
}
public override void WriteByte (byte value)
{
throw new System.NotSupportedException ("SoundInput.WriteByte method is not supported");
}
#endregion
#region IDisposable Members
bool disposed = false;
protected override void Dispose (bool disposing)
{
if (!disposed)
{
if (disposing)
{
m_input.Dispose();
}
disposed = true;
base.Dispose (disposing);
}
}
#endregion
}
public abstract class AudioFormat : IResource
{
public override string Type { get { return "audio"; } }
public abstract SoundInput TryOpen (Stream file);
public static SoundInput Read (Stream file)
{
var input = new MemoryStream();
file.CopyTo (input);
try
{
var sound = FindFormat (input);
if (null != sound)
input = null; // input stream is owned by sound object now, don't dispose it
return sound;
}
finally
{
if (null != input)
input.Dispose();
}
}
public static SoundInput FindFormat (Stream file)
{
uint signature = FormatCatalog.ReadSignature (file);
for (;;)
{
var range = FormatCatalog.Instance.LookupSignature<AudioFormat> (signature);
foreach (var impl in range)
{
try
{
file.Position = 0;
SoundInput sound = impl.TryOpen (file);
if (null != sound)
return sound;
}
catch { }
}
if (0 == signature)
break;
signature = 0;
}
return null;
}
}
}

158
GameRes/AudioWAV.cs Normal file
View File

@ -0,0 +1,158 @@
//! \file AudioWAV.cs
//! \date Tue Nov 04 18:22:37 2014
//! \brief WAVE audio format implementation.
//
// Copyright (C) 2014 by morkt
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//
using System.ComponentModel.Composition;
using System.IO;
namespace GameRes
{
public class WaveInput : SoundInput
{
long m_data_offset;
public override long Position
{
get { return m_input.Position - m_data_offset; }
set { m_input.Position = m_data_offset + value; }
}
public override bool CanSeek { get { return m_input.CanSeek; } }
public override int SourceBitrate
{
get { return (int)Format.AverageBytesPerSecond * 8; }
}
public WaveInput (Stream file) : base (file)
{
using (var input = new BinaryReader (m_input, System.Text.Encoding.UTF8, true))
{
input.BaseStream.Seek (8, SeekOrigin.Current);
uint header = input.ReadUInt32();
if (header != 0x45564157)
throw new InvalidFormatException ("Invalid WAVE file format.");
bool found_fmt = false;
bool found_data = false;
long current_offset = input.BaseStream.Position;
while (!found_fmt || !found_data)
{
uint header0 = input.ReadUInt32();
uint header1 = input.ReadUInt32();
if (!found_fmt && 0x20746d66 == header0)
{
if (header1 < 0x10)
throw new InvalidFormatException ("Invalid WAVE file format");
ushort tag = input.ReadUInt16();
if (1 != tag)
throw new InvalidFormatException ("Unsupported WAVE file format.");
var format = new WaveFormat();
format.FormatTag = tag;
format.Channels = input.ReadUInt16();
format.SamplesPerSecond = input.ReadUInt32();
format.AverageBytesPerSecond = input.ReadUInt32();
format.BlockAlign = input.ReadUInt16();
format.BitsPerSample = input.ReadUInt16();
this.Format = format;
found_fmt = true;
current_offset += 8 + ((header1 + 1) & ~1);
input.BaseStream.Seek (current_offset, SeekOrigin.Begin);
continue;
}
if (!found_data && 0x61746164 == header0)
{
found_data = true;
m_data_offset = current_offset + 8;
this.PcmSize = header1;
if (found_fmt)
break;
}
long chunk_size = (header1 + 1) & ~1;
input.BaseStream.Seek (chunk_size, SeekOrigin.Current);
current_offset += 8 + chunk_size;
}
this.Reset();
}
}
public override void Reset ()
{
m_input.Seek (m_data_offset, SeekOrigin.Begin);
}
public override long Seek (long offset, SeekOrigin origin)
{
if (SeekOrigin.Begin == origin)
offset += m_data_offset;
else if (SeekOrigin.Current == origin)
offset = m_input.Position + offset;
else if (SeekOrigin.End == origin)
offset = m_data_offset + PcmSize + offset;
if (offset < m_data_offset)
offset = m_data_offset;
else if (offset > m_data_offset + PcmSize)
offset = m_data_offset + PcmSize;
offset = m_input.Seek (offset, SeekOrigin.Begin);
return offset - m_data_offset;
}
public override int Read (byte[] buffer, int offset, int count)
{
long remaining = PcmSize - Position;
if (count > remaining)
count = (int)remaining;
return m_input.Read (buffer, offset, count);
}
public override int ReadByte ()
{
if (Position < PcmSize)
return m_input.ReadByte();
else
return -1;
}
}
[Export(typeof(AudioFormat))]
public class WaveAudio : AudioFormat
{
public override string Tag { get { return "WAV"; } }
public override string Description { get { return "Wave audio format"; } }
public override uint Signature { get { return 0x46464952; } } // 'RIFF'
public override SoundInput TryOpen (Stream file)
{
return new WaveInput (file);
}
}
}

View File

@ -276,6 +276,8 @@ namespace GameRes
private IEnumerable<ArchiveFormat> m_arc_formats;
[ImportMany(typeof(ImageFormat))]
private IEnumerable<ImageFormat> m_image_formats;
[ImportMany(typeof(AudioFormat))]
private IEnumerable<AudioFormat> m_audio_formats;
[ImportMany(typeof(ScriptFormat))]
private IEnumerable<ScriptFormat> m_script_formats;
#pragma warning restore 649
@ -288,6 +290,7 @@ namespace GameRes
public IEnumerable<ArchiveFormat> ArcFormats { get { return m_arc_formats; } }
public IEnumerable<ImageFormat> ImageFormats { get { return m_image_formats; } }
public IEnumerable<AudioFormat> AudioFormats { get { return m_audio_formats; } }
public IEnumerable<ScriptFormat> ScriptFormats { get { return m_script_formats; } }
public Exception LastError { get; set; }
@ -310,6 +313,7 @@ namespace GameRes
container.ComposeParts (this);
AddResourceImpl (m_arc_formats);
AddResourceImpl (m_image_formats);
AddResourceImpl (m_audio_formats);
AddResourceImpl (m_script_formats);
}

View File

@ -51,6 +51,8 @@
<ItemGroup>
<Compile Include="ArcFile.cs" />
<Compile Include="ArcView.cs" />
<Compile Include="Audio.cs" />
<Compile Include="AudioWAV.cs" />
<Compile Include="GameRes.cs" />
<Compile Include="Image.cs" />
<Compile Include="ImageBMP.cs" />