Program.cs 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638
  1. using NAudio.Wave;
  2. using System;
  3. using System.Collections.Concurrent;
  4. using System.IO;
  5. using System.Linq;
  6. using System.Net;
  7. using System.Net.Sockets;
  8. using System.Text;
  9. using System.Threading;
  10. using System.Threading.Tasks;
  11. // ReSharper disable AccessToModifiedClosure
  12. namespace AudioNTR
  13. {
  14. internal class Program
  15. {
  16. private static void Main(string[] args)
  17. {
  18. var op = args.FirstOrDefault() ?? "";
  19. var argsToOp = args.Skip(1).ToArray();
  20. Console.WriteLine("Audio Net Transmitter Receiver");
  21. switch (op.ToLower())
  22. {
  23. default:
  24. Console.WriteLine("Usage: AudioNTR <op> [args1[ args2[...]]]");
  25. Console.WriteLine(" capture");
  26. Console.WriteLine(" Test run WasapiLoopbackCapture");
  27. Console.WriteLine(" playback");
  28. Console.WriteLine(" Test run WasapiOut (sin wave)");
  29. Console.WriteLine(" playback-echo");
  30. Console.WriteLine(" Test run WasapiOut (WasapiLoopbackCapture)");
  31. Console.WriteLine(" playback-echo-2");
  32. Console.WriteLine(" Test run WasapiOut (WasapiLoopbackCapture)");
  33. Console.WriteLine(" receiver");
  34. Console.WriteLine(" <port> [bind-address] Run as Receiver");
  35. Console.WriteLine(" transmitter");
  36. Console.WriteLine(" <target-address> <port> Run as Transmitter Captures default audio output");
  37. Console.WriteLine(" transmitter-sine-wave");
  38. Console.WriteLine(" <target-address> <port> Run as Transmitter Sine wave");
  39. Console.WriteLine(" receiver-as-client");
  40. Console.WriteLine(" <target-address> <port> Run receiver as client");
  41. Console.WriteLine(" transmitter-as-server");
  42. Console.WriteLine(" <target-address> <port> Run transmitter as server Captures default audio output");
  43. break;
  44. case "capture": TestRunCapture(argsToOp); break;
  45. case "playback": TestRunPlayBack(argsToOp); break;
  46. case "playback-echo": TestRunPlayBackEcho(argsToOp); break;
  47. case "playback-echo-2": TestRunPlayBackEcho2(argsToOp); break;
  48. case "receiver": RunReceiver(argsToOp); break;
  49. case "transmitter": RunTransmitter(argsToOp); break;
  50. case "transmitter-sine-wave": RunTransmitterSineWave(argsToOp); break;
  51. case "receiver-as-client": RunReceiverAsClient(argsToOp); break;
  52. case "transmitter-as-server": RunTransmitterAsServer(argsToOp); break;
  53. }
  54. }
  55. private static void RunTransmitterAsServer(string[] argsToOp)
  56. {
  57. if (argsToOp.Length < 1) throw new ArgumentException("least 1 args for listen port");
  58. if (false == int.TryParse(argsToOp[0], out var port)) throw new ArgumentException("invalid port");
  59. IPAddress address = null;
  60. if (argsToOp.Length > 1 && false == IPAddress.TryParse(argsToOp[1], out address)) throw new ArgumentException("invalid address");
  61. Console.WriteLine("Creating TcpListener...");
  62. var listener = new TcpListener(address ?? IPAddress.Any, port);
  63. Console.WriteLine("Start Listening...");
  64. listener.Start();
  65. Console.WriteLine($"Listening on {listener.LocalEndpoint}");
  66. var running = true;
  67. var task = Task.Run(() =>
  68. {
  69. while (running)
  70. {
  71. Console.WriteLine("Waiting connection...");
  72. var client = listener.AcceptTcpClient();
  73. client.NoDelay = true;
  74. Console.WriteLine($"Accept connection from {client.Client.RemoteEndPoint}...");
  75. var stream = client.GetStream();
  76. Console.WriteLine("Creating WasapiLoopbackCapture Instance...");
  77. var provider = new WasapiLoopbackCapture();
  78. Console.WriteLine("Sending wave format ...");
  79. var writer = new BinaryWriter(stream, Encoding.UTF8, true);
  80. provider.WaveFormat.Serialize(writer);
  81. writer.Close();
  82. Console.WriteLine("Begin sending chunks...");
  83. long totalSent = 0;
  84. var up = DateTime.Now;
  85. var connectAlive = true;
  86. provider.DataAvailable += (sender, args) =>
  87. {
  88. Console.Title = $"Sent bytes: {totalSent:N0}, UP: {DateTime.Now - up}";
  89. try
  90. {
  91. stream.Write(args.Buffer, 0, args.BytesRecorded);
  92. stream.Flush();
  93. }
  94. catch (Exception e)
  95. {
  96. Console.WriteLine($"connection lost:{e.Message}");
  97. connectAlive = false;
  98. return;
  99. }
  100. totalSent += args.BytesRecorded;
  101. };
  102. provider.StartRecording();
  103. while (running && connectAlive) Thread.Sleep(100);
  104. provider.StopRecording();
  105. }
  106. });
  107. Console.WriteLine("Press ENTER to Exit.");
  108. Console.ReadLine();
  109. running = false;
  110. task.Wait();
  111. Console.WriteLine("Finished.");
  112. }
  113. private static void RunReceiverAsClient(string[] argsToOp)
  114. {
  115. const int bufferMs = 500;
  116. if (argsToOp.Length != 2) throw new ArgumentException("required 2 args for address and port");
  117. if (false == IPAddress.TryParse(argsToOp[0], out var address)) throw new ArgumentException("invalid address");
  118. if (false == int.TryParse(argsToOp[1], out var port)) throw new ArgumentException("invalid port");
  119. var running = true;
  120. var task = Task.Run(() =>
  121. {
  122. do
  123. {
  124. TcpClient client = null;
  125. try
  126. {
  127. Console.WriteLine("Creating TcpClient ...");
  128. client = new TcpClient { NoDelay = true };
  129. var ipEndPoint = new IPEndPoint(address, port);
  130. Console.WriteLine($"Connecting to {ipEndPoint} ...");
  131. client.Connect(ipEndPoint);
  132. var stream = client.GetStream();
  133. Console.WriteLine("Parsing wave format and create BufferedWaveProvider...");
  134. var reader = new BinaryReader(stream, Encoding.UTF8, true);
  135. var provider = new BufferedWaveProvider(new WaveFormat(reader))
  136. {
  137. BufferDuration = TimeSpan.FromMilliseconds(bufferMs),
  138. DiscardOnBufferOverflow = true,
  139. };
  140. reader.Dispose();
  141. Console.WriteLine($"Encoding: {provider.WaveFormat.Encoding}");
  142. Console.WriteLine($"Channels: {provider.WaveFormat.Channels}");
  143. Console.WriteLine($"SampleRate: {provider.WaveFormat.SampleRate}");
  144. Console.WriteLine($"BitsPerSample: {provider.WaveFormat.BitsPerSample}");
  145. Console.WriteLine($"Buffer Duration set to {provider.BufferDuration}");
  146. Console.WriteLine("Creating WasapiOut Instance...");
  147. var output = new WasapiOut();
  148. Console.WriteLine("Setup...");
  149. output.Init(provider);
  150. const int fillSleep = bufferMs * 11 / 20;
  151. Console.WriteLine($"Filling buffer, sleep {fillSleep}ms");
  152. Thread.Sleep(fillSleep);
  153. Console.WriteLine("Starting play...");
  154. output.Play();
  155. try
  156. {
  157. var buf = new byte[1024 * 1024];//1MB
  158. int readCount;
  159. Console.WriteLine("Begin read chunks...");
  160. do
  161. {
  162. Console.Title = $"Buffered bytes: {provider.BufferedBytes:N0}";
  163. readCount = stream.Read(buf, 0, buf.Length);
  164. provider.AddSamples(buf, 0, readCount);
  165. } while (readCount > 0 && running);
  166. }
  167. catch (Exception e)
  168. {
  169. Console.WriteLine(e);
  170. }
  171. Console.WriteLine("Closing connection...");
  172. client.Close();
  173. provider.ClearBuffer();
  174. Console.WriteLine("Stopping Playing...");
  175. output.Stop();
  176. Console.WriteLine("Free resources");
  177. client.Dispose();
  178. }
  179. catch (Exception e)
  180. {
  181. Console.WriteLine(e);
  182. if (running)
  183. {
  184. Console.WriteLine("Wait 10 Seconds to re connection");
  185. Thread.Sleep(10 * 1000);
  186. }
  187. }
  188. finally
  189. {
  190. Console.WriteLine("Free resources");
  191. client?.Close();
  192. client?.Dispose();
  193. }
  194. } while (running);
  195. });
  196. Console.WriteLine("Press ENTER to exit");
  197. Console.ReadLine();
  198. running = false;
  199. task.Wait();
  200. Console.WriteLine("Finished.");
  201. }
  202. private static void TestRunCapture(string[] argsToOp)
  203. {
  204. Console.WriteLine("Creating WasapiLoopbackCapture Instance...");
  205. var capture = new WasapiLoopbackCapture();
  206. Console.WriteLine($"Encoding: {capture.WaveFormat.Encoding}");
  207. Console.WriteLine($"Channels: {capture.WaveFormat.Channels}");
  208. Console.WriteLine($"SampleRate: {capture.WaveFormat.SampleRate:N0}");
  209. Console.WriteLine($"BitsPerSample:{capture.WaveFormat.BitsPerSample:N0}");
  210. var bytes = 0;
  211. capture.DataAvailable += (_, e) =>
  212. {
  213. bytes += e.BytesRecorded;
  214. Console.Title = $"Buffer: {e.Buffer.Length} Bytes: {e.BytesRecorded:N0} Total: {bytes:N0}";
  215. };
  216. Console.WriteLine("Starting capture...");
  217. capture.StartRecording();
  218. Console.WriteLine("Capturing, Press ENTER to exit");
  219. Console.ReadLine();
  220. Console.WriteLine("Stopping capture...");
  221. capture.StopRecording();
  222. Console.WriteLine("Stopped.");
  223. }
  224. private static void TestRunPlayBack(string[] argsToOp)
  225. {
  226. Console.WriteLine("Creating WasapiOut Instance...");
  227. var output = new WasapiOut();
  228. Console.WriteLine("Creating SineWaveSampleProvider Instance...");
  229. var provider = new SineWaveSampleProvider();
  230. Console.WriteLine("Init...");
  231. output.Init(provider);
  232. Console.WriteLine("Starting play...");
  233. output.Play();
  234. Console.WriteLine("Playing, Press ENTER to exit");
  235. Console.ReadLine();
  236. Console.WriteLine("Stopping Playing...");
  237. output.Stop();
  238. Console.WriteLine("Stopped.");
  239. }
  240. private static void TestRunPlayBackEcho(string[] argsToOp)
  241. {
  242. Console.WriteLine("Creating WasapiOut Instance...");
  243. var output = new WasapiOut();
  244. Console.WriteLine("Creating WaveInProvider Instance by WasapiLoopbackCapture...");
  245. var provider = new WaveInProvider(new WasapiLoopbackCapture());
  246. Console.WriteLine("Init...");
  247. output.Init(provider);
  248. //output.Volume = 0.5f;
  249. Console.WriteLine("Starting Capture...");
  250. provider.StartRecording();
  251. Console.WriteLine("Starting play...");
  252. output.Play();
  253. Console.WriteLine("Playing, Press ENTER to exit");
  254. Console.ReadLine();
  255. Console.WriteLine("Stopping Capture...");
  256. provider.StopRecording();
  257. Console.WriteLine("Stopping Playing...");
  258. output.Stop();
  259. Console.WriteLine("Stopped.");
  260. }
  261. private static void TestRunPlayBackEcho2(string[] argsToOp)
  262. {
  263. Console.WriteLine("Creating WasapiOut Instance...");
  264. var output = new WasapiOut();
  265. Console.WriteLine("Creating WasapiLoopbackCapture Instance...");
  266. var capture = new WasapiLoopbackCapture();
  267. Console.WriteLine("Creating WasapiLoopbackCapture Instance...");
  268. var provider = new BufferedWaveProvider(capture.WaveFormat);
  269. Console.WriteLine("Setup...");
  270. capture.DataAvailable += (sender, args) => provider.AddSamples(args.Buffer, 0, args.BytesRecorded);
  271. output.Init(provider);
  272. Console.WriteLine("Starting Capture...");
  273. capture.StartRecording();
  274. Console.WriteLine("Starting play...");
  275. output.Play();
  276. Console.WriteLine("Playing, Press ENTER to exit");
  277. Console.ReadLine();
  278. Console.WriteLine("Stopping Capture...");
  279. capture.StopRecording();
  280. Console.WriteLine("Free resoures...");
  281. provider.ClearBuffer();
  282. Console.WriteLine("Stopping Playing...");
  283. output.Stop();
  284. Console.WriteLine("Stopped.");
  285. }
  286. private static void RunReceiver(string[] argsToOp)
  287. {
  288. const int bufferMs = 500;
  289. if (argsToOp.Length < 1) throw new ArgumentException("least 1 args for listen port");
  290. if (false == int.TryParse(argsToOp[0], out var port)) throw new ArgumentException("invalid port");
  291. IPAddress address = null;
  292. if (argsToOp.Length > 1 && false == IPAddress.TryParse(argsToOp[1], out address)) throw new ArgumentException("invalid address");
  293. Console.WriteLine("Creating TcpListener...");
  294. var listener = new TcpListener(address ?? IPAddress.Any, port);
  295. Console.WriteLine("Start Listening...");
  296. listener.Start();
  297. Console.WriteLine($"Listening on {listener.LocalEndpoint}");
  298. var running = true;
  299. var task = Task.Run(() =>
  300. {
  301. while (running)
  302. {
  303. Console.WriteLine("Waiting connection...");
  304. var client = listener.AcceptTcpClient();
  305. client.NoDelay = true;
  306. Console.WriteLine($"Accept connection from {client.Client.RemoteEndPoint}...");
  307. var stream = client.GetStream();
  308. Console.WriteLine("Parsing wave format and create BufferedWaveProvider...");
  309. var reader = new BinaryReader(stream, Encoding.UTF8, true);
  310. var provider = new BufferedWaveProvider(new WaveFormat(reader))
  311. {
  312. BufferDuration = TimeSpan.FromMilliseconds(bufferMs),
  313. DiscardOnBufferOverflow = true,
  314. };
  315. reader.Dispose();
  316. Console.WriteLine($"Encoding: {provider.WaveFormat.Encoding}");
  317. Console.WriteLine($"Channels: {provider.WaveFormat.Channels}");
  318. Console.WriteLine($"SampleRate: {provider.WaveFormat.SampleRate}");
  319. Console.WriteLine($"BitsPerSample: {provider.WaveFormat.BitsPerSample}");
  320. Console.WriteLine($"Buffer Duration set to {provider.BufferDuration}");
  321. Console.WriteLine("Creating WasapiOut Instance...");
  322. var output = new WasapiOut();
  323. Console.WriteLine("Setup...");
  324. output.Init(provider);
  325. const int fillSleep = bufferMs * 11 / 20;
  326. Console.WriteLine($"Filling buffer, sleep {fillSleep}ms");
  327. Thread.Sleep(fillSleep);
  328. Console.WriteLine("Starting play...");
  329. output.Play();
  330. try
  331. {
  332. var buf = new byte[1024 * 1024];//1MB
  333. int readCount;
  334. //Console.WriteLine("Sending ACK...");
  335. //stream.WriteByte(1);
  336. Console.WriteLine("Begin read chunks...");
  337. do
  338. {
  339. Console.Title = $"Buffered bytes: {provider.BufferedBytes:N0}";
  340. readCount = stream.Read(buf, 0, buf.Length);
  341. provider.AddSamples(buf, 0, readCount);
  342. } while (readCount > 0 && running);
  343. }
  344. catch (Exception e)
  345. {
  346. Console.WriteLine(e);
  347. }
  348. Console.WriteLine("Closing connection...");
  349. client.Close();
  350. provider.ClearBuffer();
  351. Console.WriteLine("Stopping Playing...");
  352. output.Stop();
  353. Console.WriteLine("Free resources");
  354. client.Dispose();
  355. }
  356. });
  357. Console.WriteLine("Press ENTER to Exit.");
  358. Console.ReadLine();
  359. running = false;
  360. task.Wait();
  361. Console.WriteLine("Finished.");
  362. }
  363. private static void RunTransmitterSineWave(string[] argsToOp)
  364. {
  365. if (argsToOp.Length != 2) throw new ArgumentException("required 2 args for address and port");
  366. if (false == IPAddress.TryParse(argsToOp[0], out var address)) throw new ArgumentException("invalid address");
  367. if (false == int.TryParse(argsToOp[1], out var port)) throw new ArgumentException("invalid port");
  368. var running = true;
  369. var task = Task.Run(() =>
  370. {
  371. do
  372. {
  373. TcpClient client = null;
  374. try
  375. {
  376. Console.WriteLine("Creating TcpClient ...");
  377. client = new TcpClient();
  378. var ipEndPoint = new IPEndPoint(address, port);
  379. Console.WriteLine($"Connecting to {ipEndPoint} ...");
  380. client.Connect(ipEndPoint);
  381. var stream = client.GetStream();
  382. Console.WriteLine("Connected, creating SineWaveSampleProvider ...");
  383. var provider = new SineWaveSampleProvider();
  384. Console.WriteLine("Sending wave format ...");
  385. var writer = new BinaryWriter(stream, Encoding.UTF8, true);
  386. provider.WaveFormat.Serialize(writer);
  387. writer.Close();
  388. Console.WriteLine("Begin sending chunks...");
  389. var buffer = new byte[provider.WaveFormat.AverageBytesPerSecond / 4];
  390. while (running)
  391. {
  392. provider.Read(buffer, 0, buffer.Length);
  393. stream.Write(buffer, 0, buffer.Length);
  394. }
  395. }
  396. catch (Exception e)
  397. {
  398. Console.WriteLine(e);
  399. if (running)
  400. {
  401. Console.WriteLine("Wait 10 Seconds to re connection");
  402. Thread.Sleep(10 * 1000);
  403. }
  404. }
  405. finally
  406. {
  407. Console.WriteLine("Free resources");
  408. client?.Close();
  409. client?.Dispose();
  410. }
  411. } while (running);
  412. });
  413. Console.WriteLine("Press ENTER to exit");
  414. Console.ReadLine();
  415. running = false;
  416. task.Wait();
  417. Console.WriteLine("Finished.");
  418. }
  419. private static void RunTransmitter(string[] argsToOp)
  420. {
  421. if (argsToOp.Length != 2) throw new ArgumentException("required 2 args for address and port");
  422. if (false == IPAddress.TryParse(argsToOp[0], out var address)) throw new ArgumentException("invalid address");
  423. if (false == int.TryParse(argsToOp[1], out var port)) throw new ArgumentException("invalid port");
  424. var running = true;
  425. var task = Task.Run(() =>
  426. {
  427. do
  428. {
  429. TcpClient client = null;
  430. try
  431. {
  432. Console.WriteLine("Creating TcpClient ...");
  433. client = new TcpClient { NoDelay = true };
  434. var ipEndPoint = new IPEndPoint(address, port);
  435. Console.WriteLine($"Connecting to {ipEndPoint} ...");
  436. client.Connect(ipEndPoint);
  437. var stream = client.GetStream();
  438. Console.WriteLine("Creating WasapiLoopbackCapture Instance...");
  439. var provider = new WasapiLoopbackCapture();
  440. Console.WriteLine("Sending wave format ...");
  441. var writer = new BinaryWriter(stream, Encoding.UTF8, true);
  442. provider.WaveFormat.Serialize(writer);
  443. writer.Close();
  444. //Console.WriteLine("Waiting ACK ...");
  445. //var ack = stream.ReadByte();
  446. //if (ack != 1) throw new Exception("Unexpected ACK");
  447. Console.WriteLine("Begin sending chunks...");
  448. long totalSent = 0;
  449. var up = DateTime.Now;
  450. provider.DataAvailable += (sender, args) =>
  451. {
  452. Console.Title = $"Sent bytes: {totalSent:N0}, UP: {DateTime.Now - up}";
  453. stream.Write(args.Buffer, 0, args.BytesRecorded);
  454. stream.Flush();
  455. totalSent += args.BytesRecorded;
  456. };
  457. provider.StartRecording();
  458. while (running) Thread.Sleep(100);
  459. provider.StopRecording();
  460. }
  461. catch (Exception e)
  462. {
  463. Console.WriteLine(e);
  464. if (running)
  465. {
  466. Console.WriteLine("Wait 10 Seconds to re connection");
  467. Thread.Sleep(10 * 1000);
  468. }
  469. }
  470. finally
  471. {
  472. Console.WriteLine("Free resources");
  473. client?.Close();
  474. client?.Dispose();
  475. }
  476. } while (running);
  477. });
  478. Console.WriteLine("Press ENTER to exit");
  479. Console.ReadLine();
  480. running = false;
  481. task.Wait();
  482. Console.WriteLine("Finished.");
  483. }
  484. }
  485. internal class WaveInProvider : IWaveProvider
  486. {
  487. private readonly IWaveIn _input;
  488. private readonly BlockingCollection<byte> _buffer;
  489. private readonly CancellationTokenSource _cancellationTokenSource = new();
  490. public WaveFormat WaveFormat { get; }
  491. public WaveInProvider(IWaveIn input, int msBuffer = 1000)
  492. {
  493. _input = input;
  494. WaveFormat = _input.WaveFormat;
  495. _input.DataAvailable += Input_DataAvailable;
  496. _buffer = new((int)Math.Ceiling(WaveFormat.SampleRate / 1000f * msBuffer * WaveFormat.Channels * (WaveFormat.BitsPerSample / 8f)));
  497. }
  498. private void Input_DataAvailable(object sender, WaveInEventArgs e)
  499. {
  500. if (_cancellationTokenSource.IsCancellationRequested) return;
  501. for (var i = 0; i < e.BytesRecorded; i++) _buffer.Add(e.Buffer[i], _cancellationTokenSource.Token);
  502. }
  503. public void StartRecording()
  504. {
  505. _input.StartRecording();
  506. }
  507. public void StopRecording()
  508. {
  509. _input.StopRecording();
  510. _cancellationTokenSource.Cancel();
  511. }
  512. public int Read(byte[] buffer, int offset, int count)
  513. {
  514. var readCount = 0;
  515. var eof = offset + count;
  516. do
  517. {
  518. try
  519. {
  520. buffer[offset] = _buffer.Take(_cancellationTokenSource.Token);
  521. }
  522. catch (OperationCanceledException)
  523. {
  524. return readCount;
  525. }
  526. readCount++;
  527. offset++;
  528. } while (_buffer.Count > 0 && offset < eof && _cancellationTokenSource.IsCancellationRequested == false);
  529. return readCount;
  530. }
  531. }
  532. internal class SineWaveSampleProvider : IWaveProvider, ISampleProvider
  533. {
  534. public int Freq { get; }
  535. public float Amp { get; }
  536. public WaveFormat WaveFormat { get; }
  537. private int _sample;
  538. public SineWaveSampleProvider(int sampleRate = 441000, int channels = 1, int freq = 1000, float amp = 0.25f)
  539. {
  540. Freq = freq;
  541. Amp = amp;
  542. WaveFormat = WaveFormat.CreateIeeeFloatWaveFormat(sampleRate, channels);
  543. }
  544. public int Read(byte[] buffer, int offset, int count)
  545. {
  546. var waveBuffer = new WaveBuffer(buffer);
  547. var samplesRequired = count / 4;
  548. var samplesRead = Read(waveBuffer.FloatBuffer, offset / 4, samplesRequired);
  549. return samplesRead * 4;
  550. }
  551. public int Read(float[] buffer, int offset, int sampleCount)
  552. {
  553. var sampleRate = WaveFormat.SampleRate;
  554. for (var n = 0; n < sampleCount; n++)
  555. {
  556. buffer[n + offset] = (float)(Amp * Math.Sin((2 * Math.PI * _sample * Freq) / sampleRate));
  557. _sample++;
  558. if (_sample >= sampleRate) _sample = 0;
  559. }
  560. return sampleCount;
  561. }
  562. }
  563. }