Program.cs 27 KB

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