DsfAudioStream.cs 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182
  1. using System.Text;
  2. using NAudio.Wave;
  3. namespace Bmp.Core.Lite.Playback.Inputs;
  4. public class DsfAudioStream : DsdAudioStream,IHaveDecoderInfo
  5. {
  6. public const string SIGNATURE_DSD = "DSD ";
  7. private const string SIGNATURE_FMT = "fmt ";
  8. private const string SIGNATURE_DATA = "data";
  9. string IHaveDecoderInfo.DecoderName => "DSF";
  10. string? IHaveDecoderInfo.FileFormat => $"V{_formatVersion}";
  11. private readonly Stream _underlyingStream;
  12. private readonly bool _disposeStream;
  13. private readonly long _dataChunkBeginOffset;
  14. private readonly long _dataChunkEndOffset;
  15. private readonly long _dataSize;
  16. private readonly long _pointerToMetadataChunk;
  17. public int ChannelNum { get; }
  18. public int SampleRate { get; }
  19. public int ClusterSizePerChannel { get; }
  20. public int BitPerSample { get; }
  21. public override WaveFormat WaveFormat { get; }
  22. private readonly byte[] _clusterBuf;
  23. private int _clusterBufSize;
  24. private int _clusterPtrByChannel;
  25. private readonly int _formatVersion;
  26. public static bool IsDsfFile(Stream stream)
  27. {
  28. if (stream.Length > 4)
  29. {
  30. using var binaryReader = new BinaryReader(stream, Encoding.UTF8, true);
  31. var signatureDSD = Encoding.ASCII.GetString(binaryReader.ReadBytes(4));
  32. if (signatureDSD == SIGNATURE_DSD) return true;
  33. }
  34. return false;
  35. }
  36. public DsfAudioStream(string urlOrPath) : this(InputSourceProviderLite.ReadContentAsSeekableStream(urlOrPath), true)
  37. {
  38. }
  39. public DsfAudioStream(Stream underlyingStream, bool disposeStream)
  40. {
  41. if (underlyingStream.CanSeek == false) throw new ArgumentException("stream not seekable");
  42. _underlyingStream = underlyingStream;
  43. _disposeStream = disposeStream;
  44. if (_underlyingStream.Length < 4) throw new InvalidDataException("too small as dsf file");
  45. _underlyingStream.Position = 0;
  46. using var reader = new BinaryReader(_underlyingStream, Encoding.UTF8, true);
  47. var dsdSignature = Encoding.ASCII.GetString(reader.ReadBytes(4));
  48. if (SIGNATURE_DSD != dsdSignature) throw new InvalidDataException("invalid DSD signature");
  49. var dsdSizeOfThisChunk = reader.ReadInt64();
  50. if (dsdSizeOfThisChunk != 28) throw new InvalidDataException("invalid dsd chunk size");
  51. var totalFileSize = reader.ReadInt64();
  52. if (totalFileSize != _underlyingStream.Length) throw new InvalidDataException("invalid total file size");
  53. _pointerToMetadataChunk = reader.ReadInt64();
  54. var fmtSignature = Encoding.ASCII.GetString(reader.ReadBytes(4));
  55. if (SIGNATURE_FMT != fmtSignature) throw new InvalidDataException("invalid FMT signature");
  56. var fmtSizeOfThisChunk = reader.ReadInt64();
  57. if (fmtSizeOfThisChunk != 52) throw new NotSupportedException("not supported fmt chunk size");
  58. _formatVersion = reader.ReadInt32();
  59. var formatId = reader.ReadInt32();
  60. if (formatId != 0) throw new NotSupportedException("only DSD raw supported");
  61. var channelType = reader.ReadInt32();
  62. ChannelNum = reader.ReadInt32();
  63. SampleRate = reader.ReadInt32();
  64. BitPerSample = reader.ReadInt32();
  65. var sampleCount = reader.ReadInt64();
  66. ClusterSizePerChannel = reader.ReadInt32();
  67. var rsv0000 = reader.ReadInt32();
  68. var dataSignature = Encoding.ASCII.GetString(reader.ReadBytes(4));
  69. if (SIGNATURE_DATA != dataSignature) throw new InvalidDataException("invalid data signature");
  70. var dataSizeOfThisChunk = reader.ReadInt64();
  71. _dataSize = dataSizeOfThisChunk - 12;
  72. _dataChunkBeginOffset = _underlyingStream.Position;
  73. _dataChunkEndOffset = _dataChunkBeginOffset + _dataSize;
  74. var align = ClusterSizePerChannel * ChannelNum;
  75. WaveFormat = WaveFormat.CreateCustomFormat(WaveFormatEncoding.Unknown, SampleRate, ChannelNum, SampleRate * channelType / 8, align, 1);
  76. _clusterBuf = new byte[align];
  77. }
  78. private bool ReadCluster()
  79. {
  80. // block[ChannelNum]
  81. // blockPtr
  82. // blockSize = Chunk/ChannelNum
  83. var readCount = 0;
  84. do
  85. {
  86. var safeCount = Math.Min(_clusterBuf.Length - readCount, _dataChunkEndOffset - _underlyingStream.Position);
  87. if (safeCount <= 0) break;
  88. var read = _underlyingStream.Read(_clusterBuf, readCount, (int)safeCount);
  89. if (read == 0) break;
  90. readCount += read;
  91. } while (readCount < _clusterBuf.Length);
  92. _clusterBufSize = readCount;
  93. _clusterPtrByChannel = 0;
  94. return readCount != 0;
  95. }
  96. public override int Read(byte[] buffer, int offset, int countRequired)
  97. {
  98. if (countRequired == 0) return 0;
  99. if (countRequired < ChannelNum) throw new ArgumentOutOfRangeException(nameof(countRequired));
  100. var mod = countRequired % ChannelNum;
  101. var count = countRequired;
  102. if (mod != 0) count -= mod;
  103. //对齐 BlockSizePerChannel 声道交替字节 (FAKE BIT PER SAMPLE 8bit) or ( 16 SHORT/ 32 INT/ 64 LONG)
  104. //Source L[BlockSizePerChannel] R[BlockSizePerChannel] L[BlockSizePerChannel] R[BlockSizePerChannel] -> Transfer LR LR LR LR
  105. if (_clusterBufSize == 0)
  106. {
  107. if (ReadCluster() == false) return 0;
  108. }
  109. var bytes = count / ChannelNum;
  110. var dstPtr = 0;
  111. //TODO: optimization Unsafe moving ptr
  112. for (var s = 0; s < bytes; s++)
  113. {
  114. for (var ch = 0; ch < ChannelNum; ch++)
  115. {
  116. var srcPtr = ch * ClusterSizePerChannel + _clusterPtrByChannel;
  117. buffer[dstPtr] = _clusterBuf[srcPtr];
  118. ++dstPtr;
  119. }
  120. _clusterPtrByChannel++;
  121. if (_clusterPtrByChannel * ChannelNum == _clusterBufSize)
  122. {
  123. if (!ReadCluster()) break;
  124. }
  125. }
  126. return dstPtr;
  127. }
  128. public override long Length => _dataSize;
  129. public override long Position
  130. {
  131. get => _underlyingStream.Position - _dataChunkBeginOffset;
  132. set => _underlyingStream.Position = _dataChunkBeginOffset + value - value % (ClusterSizePerChannel * ChannelNum);
  133. }
  134. protected override void Dispose(bool disposing)
  135. {
  136. base.Dispose(disposing);
  137. if (_disposeStream) _underlyingStream.Dispose();
  138. }
  139. }