FileHardwareDevice.cs 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116
  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.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="IHardwareDevice"/> that outputs to a wav file.
  26. /// </summary>
  27. public class FileHardwareDevice : IHardwareDevice
  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 void SetVolume(float volume)
  67. {
  68. // Do nothing, volume is not used for FileHardwareDevice at the moment.
  69. }
  70. public float GetVolume()
  71. {
  72. // FileHardwareDevice does not incorporate volume.
  73. return 0;
  74. }
  75. public uint GetChannelCount()
  76. {
  77. return _channelCount;
  78. }
  79. public uint GetSampleRate()
  80. {
  81. return _sampleRate;
  82. }
  83. public void Dispose()
  84. {
  85. Dispose(true);
  86. }
  87. protected virtual void Dispose(bool disposing)
  88. {
  89. if (disposing)
  90. {
  91. _stream?.Flush();
  92. _stream?.Dispose();
  93. _stream = null;
  94. }
  95. }
  96. }
  97. }