-
-
Notifications
You must be signed in to change notification settings - Fork 17
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #691 from b-editor/wave-support
Waveファイルを読み込めるようにした
- Loading branch information
Showing
11 changed files
with
646 additions
and
14 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,26 +1,39 @@ | ||
namespace Beutl.Media.Decoding; | ||
using Beutl.Media.Wave; | ||
|
||
namespace Beutl.Media.Decoding; | ||
|
||
public static class DecoderRegistry | ||
{ | ||
private static readonly List<IDecoderInfo> _registered = new(); | ||
private static readonly List<IDecoderInfo> s_registered = new() | ||
{ | ||
new WaveDecoderInfo() | ||
}; | ||
|
||
public static IEnumerable<IDecoderInfo> EnumerateDecoder() | ||
{ | ||
return _registered; | ||
return s_registered; | ||
} | ||
|
||
public static MediaReader? OpenMediaFile(string file, MediaOptions options) | ||
{ | ||
return GuessDecoder(file).FirstOrDefault()?.Open(file, options); | ||
foreach (IDecoderInfo decoder in GuessDecoder(file)) | ||
{ | ||
if (decoder.Open(file, options) is { } reader) | ||
{ | ||
return reader; | ||
} | ||
} | ||
|
||
return null; | ||
} | ||
|
||
public static IDecoderInfo[] GuessDecoder(string file) | ||
{ | ||
return _registered.Where(i => i.IsSupported(file)).ToArray(); | ||
return s_registered.Where(i => i.IsSupported(file)).ToArray(); | ||
} | ||
|
||
public static void Register(IDecoderInfo decoder) | ||
{ | ||
_registered.Add(decoder); | ||
s_registered.Add(decoder); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,140 @@ | ||
using static Beutl.Media.Wave.WaveBitConverter; | ||
|
||
namespace Beutl.Media.Wave; | ||
|
||
public sealed class WaveAnalysis | ||
{ | ||
public WaveAnalysis(Stream stream) | ||
{ | ||
string errormsg = "It is not a WAVE file."; | ||
|
||
// RIFF | ||
Span<byte> intBytes = stackalloc byte[4]; | ||
stream.ReadExactly(intBytes); | ||
if (!intBytes.SequenceEqual("RIFF"u8)) | ||
{ | ||
throw new Exception(errormsg); | ||
} | ||
|
||
stream.Position += 4; | ||
|
||
// WAVE | ||
stream.ReadExactly(intBytes); | ||
if (!intBytes.SequenceEqual("WAVE"u8)) | ||
{ | ||
throw new Exception(errormsg); | ||
} | ||
|
||
// fmt | ||
int len; | ||
short wFormatTag, nChannels, nBlockAlign, wBitsPerSample; | ||
int nSamplesPerSec, nAvgBytesPerSec; | ||
while (true) | ||
{ | ||
stream.ReadExactly(intBytes); | ||
if (intBytes.SequenceEqual("fmt "u8)) | ||
{ | ||
stream.ReadExactly(intBytes); | ||
len = ToInt32(intBytes); | ||
|
||
Span<byte> shortBytes = stackalloc byte[2]; | ||
|
||
// 種類(1:リニアPCM) | ||
stream.ReadExactly(shortBytes); | ||
wFormatTag = ToInt16(shortBytes); | ||
|
||
// チャンネル数(1:モノラル 2:ステレオ) | ||
stream.ReadExactly(shortBytes); | ||
nChannels = ToInt16(shortBytes); | ||
|
||
// サンプリングレート(44100=44.1kHzなど) | ||
stream.ReadExactly(intBytes); | ||
nSamplesPerSec = ToInt32(intBytes); | ||
|
||
// 平均データ転送レート(byte/sec) | ||
// ※PCMの場合はnSamplesPerSec * nBlockAlign | ||
stream.ReadExactly(intBytes); | ||
nAvgBytesPerSec = ToInt32(intBytes); | ||
|
||
// ブロックサイズ | ||
// ※PCMの場合はwBitsPerSample * nChannels / 8 | ||
stream.ReadExactly(shortBytes); | ||
nBlockAlign = ToInt16(shortBytes); | ||
|
||
// サンプルあたりのビット数 (bit/sample) | ||
// ※PCMの場合は8bit=8, 16bit =16 | ||
stream.ReadExactly(shortBytes); | ||
wBitsPerSample = ToInt16(shortBytes); | ||
|
||
// WaveFomatExなどの対策 | ||
stream.Position = stream.Position + len - 16; | ||
|
||
break; | ||
} | ||
else | ||
{ | ||
stream.ReadExactly(intBytes); | ||
len = ToInt32(intBytes); | ||
stream.Position += len; | ||
} | ||
|
||
if (stream.Position >= stream.Length) | ||
{ | ||
throw new Exception(errormsg); | ||
} | ||
} | ||
|
||
// data | ||
byte[] raw; | ||
while (true) | ||
{ | ||
stream.ReadExactly(intBytes); | ||
if (intBytes.SequenceEqual("data"u8)) | ||
{ | ||
stream.ReadExactly(intBytes); | ||
len = ToInt32(intBytes); | ||
|
||
raw = new byte[len]; | ||
stream.ReadExactly(raw); | ||
|
||
break; | ||
} | ||
else | ||
{ | ||
stream.ReadExactly(intBytes); | ||
len = ToInt32(intBytes); | ||
stream.Position += len; | ||
} | ||
|
||
if (stream.Position >= stream.Length) | ||
{ | ||
throw new Exception(errormsg); | ||
} | ||
} | ||
|
||
// WaveFomat構造体(アクセス用) | ||
WaveFomat = new WaveFormat | ||
{ | ||
FormatTag = (WaveFormatTag)wFormatTag, | ||
Channels = nChannels, | ||
SamplesPerSec = nSamplesPerSec, | ||
AvgBytesPerSec = nAvgBytesPerSec, | ||
BlockAlign = nBlockAlign, | ||
BitsPerSample = wBitsPerSample | ||
}; | ||
// 波形データ | ||
Raw = raw; | ||
// 再生時間 | ||
Duration = new Rational(len, nAvgBytesPerSec); | ||
// ビットレート (bps) | ||
Bitrate = nSamplesPerSec * wBitsPerSample * nChannels; | ||
} | ||
|
||
public WaveFormat WaveFomat { get; } | ||
|
||
public byte[] Raw { get; } | ||
|
||
public Rational Duration { get; } | ||
|
||
public int Bitrate { get; } | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,86 @@ | ||
namespace Beutl.Media.Wave; | ||
|
||
internal static class WaveBitConverter | ||
{ | ||
public static short ToInt16(ReadOnlySpan<byte> value) | ||
{ | ||
return (short)(value[1] << 8 | value[0]); | ||
} | ||
|
||
public static int ToInt24(ReadOnlySpan<byte> value) | ||
{ | ||
return value[2] << 16 | value[1] << 8 | value[0]; | ||
} | ||
|
||
public static uint ToUInt24(ReadOnlySpan<byte> value) | ||
{ | ||
return (uint)(value[2] << 16 | value[1] << 8 | value[0]); | ||
} | ||
|
||
public static int ToInt32(ReadOnlySpan<byte> value) | ||
{ | ||
return value[3] << 24 | value[2] << 16 | value[1] << 8 | value[0]; | ||
} | ||
|
||
public static float ToSingle(ReadOnlySpan<byte> value) | ||
{ | ||
return BitConverter.ToSingle(value); | ||
} | ||
|
||
public static ushort ToUInt16(ReadOnlySpan<byte> value) | ||
{ | ||
return (ushort)(value[1] << 8 | value[0]); | ||
} | ||
|
||
// Uint32からInt32へ | ||
// ※0 ~ 4294967296 から -2147483648 ~ 2147483647へ | ||
public static int ShiftInt32(uint x) | ||
{ | ||
if (2147483648 <= x) | ||
{ | ||
return (int)-(4294967296 - x); | ||
} | ||
else | ||
{ | ||
return (int)x; | ||
} | ||
} | ||
|
||
public static sbyte ShiftInt8(byte x) | ||
{ | ||
if (128 == x) return 0; | ||
|
||
if (129 >= x) | ||
{ | ||
return (sbyte)(x - 128); | ||
} | ||
else | ||
{ | ||
return (sbyte)-(128 - x); | ||
} | ||
} | ||
|
||
public static short ShiftInt16(ushort x) | ||
{ | ||
if (32768 <= x) | ||
{ | ||
return (short)-(65536 - x); | ||
} | ||
else | ||
{ | ||
return (short)x; | ||
} | ||
} | ||
|
||
public static int ShiftInt24(uint x) | ||
{ | ||
if (8388608 <= x) | ||
{ | ||
return (int)-(16777216 - x); | ||
} | ||
else | ||
{ | ||
return (int)x; | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
using Beutl.Media.Decoding; | ||
|
||
namespace Beutl.Media.Wave; | ||
|
||
public sealed class WaveDecoderInfo : IDecoderInfo | ||
{ | ||
public string Name => "Wave Reader (unsigned 8bit[PCM], signed 16bit[PCM], signed 24bit[PCM], signed 24bit[PCM], signed 32bit[PCM], 32bit float[IEEE Float])"; | ||
|
||
public IEnumerable<string> AudioExtensions() | ||
{ | ||
yield return ".wav"; | ||
yield return ".wave"; | ||
} | ||
|
||
public MediaReader? Open(string file, MediaOptions options) | ||
{ | ||
try | ||
{ | ||
return new WaveReader(file, options); | ||
} | ||
catch | ||
{ | ||
return null; | ||
} | ||
} | ||
|
||
public IEnumerable<string> VideoExtensions() | ||
{ | ||
yield break; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
namespace Beutl.Media.Wave; | ||
|
||
public record WaveFormat | ||
{ | ||
public required WaveFormatTag FormatTag { get; init; } | ||
|
||
public required short Channels { get; init; } | ||
|
||
public required int SamplesPerSec { get; init; } | ||
|
||
public required int AvgBytesPerSec { get; init; } | ||
|
||
public required short BlockAlign { get; init; } | ||
|
||
public required short BitsPerSample { get; init; } | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
namespace Beutl.Media.Wave; | ||
|
||
// https://github.com/TakeshiOkamoto/WAVE.wasm.js/tree/master | ||
public enum WaveFormatTag : short | ||
{ | ||
Pcm = 1, | ||
IeeeFloat = 3, | ||
MuLaw = 7 | ||
} |
Oops, something went wrong.