FileHardwareDevice.cs 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105
  1. //
  2. // Copyright (c) 2019-2021 Ryujinx
  3. //
  4. // This program is free software: you can redistribute it and/or modify
  5. // it under the terms of the GNU Lesser General Public License as published by
  6. // the Free Software Foundation, either version 3 of the License, or
  7. // (at your option) any later version.
  8. //
  9. // This program is distributed in the hope that it will be useful,
  10. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. // GNU Lesser General Public License for more details.
  13. //
  14. // You should have received a copy of the GNU Lesser General Public License
  15. // along with this program. If not, see <https://www.gnu.org/licenses/>.
  16. //
  17. using Ryujinx.Audio.Renderer.Integration;
  18. using System;
  19. using System.IO;
  20. using System.Runtime.InteropServices;
  21. using System.Text;
  22. namespace Ryujinx.Audio.Renderer.Utils
  23. {
  24. /// <summary>
  25. /// A <see cref="HardwareDevice"/> that outputs to a wav file.
  26. /// </summary>
  27. public class FileHardwareDevice : HardwareDevice
  28. {
  29. private FileStream _stream;
  30. private uint _channelCount;
  31. private uint _sampleRate;
  32. private const int HeaderSize = 44;
  33. public FileHardwareDevice(string path, uint channelCount, uint sampleRate)
  34. {
  35. _stream = File.OpenWrite(path);
  36. _channelCount = channelCount;
  37. _sampleRate = sampleRate;
  38. _stream.Seek(HeaderSize, SeekOrigin.Begin);
  39. }
  40. private void UpdateHeader()
  41. {
  42. var writer = new BinaryWriter(_stream);
  43. long currentPos = writer.Seek(0, SeekOrigin.Current);
  44. writer.Seek(0, SeekOrigin.Begin);
  45. writer.Write(Encoding.ASCII.GetBytes("RIFF"));
  46. writer.Write((int)(writer.BaseStream.Length - 8));
  47. writer.Write(Encoding.ASCII.GetBytes("WAVE"));
  48. writer.Write(Encoding.ASCII.GetBytes("fmt "));
  49. writer.Write(16);
  50. writer.Write((short)1);
  51. writer.Write((short)GetChannelCount());
  52. writer.Write(GetSampleRate());
  53. writer.Write(GetSampleRate() * GetChannelCount() * sizeof(short));
  54. writer.Write((short)(GetChannelCount() * sizeof(short)));
  55. writer.Write((short)(sizeof(short) * 8));
  56. writer.Write(Encoding.ASCII.GetBytes("data"));
  57. writer.Write((int)(writer.BaseStream.Length - HeaderSize));
  58. writer.Seek((int)currentPos, SeekOrigin.Begin);
  59. }
  60. public void AppendBuffer(ReadOnlySpan<short> data, uint channelCount)
  61. {
  62. _stream.Write(MemoryMarshal.Cast<short, byte>(data));
  63. UpdateHeader();
  64. _stream.Flush();
  65. }
  66. public uint GetChannelCount()
  67. {
  68. return _channelCount;
  69. }
  70. public uint GetSampleRate()
  71. {
  72. return _sampleRate;
  73. }
  74. public void Dispose()
  75. {
  76. Dispose(true);
  77. }
  78. protected virtual void Dispose(bool disposing)
  79. {
  80. if (disposing)
  81. {
  82. _stream?.Flush();
  83. _stream?.Dispose();
  84. _stream = null;
  85. }
  86. }
  87. }
  88. }