Buffer stream from microphone iterating results - c#

What i would like to do is, constantly listen the microphone, have the microphone writer that writes into a stream, when the stream has x lenght, yield result, clear the stream and keep doing it it in a loop.
Then from the caller analyse all bytes received, i am a bit new to microphone recording, i don't event know if the code below register something, I am using NAudio library:
this is the caller:
var buffers = service.StreamHearing();
foreach (var buffer in buffers)
{
//analyse
}
and then is the actual service:
public IEnumerable<byte[]> StreamHearing()
{
var buffer = new byte[512];
using(var stream = new MemoryStream(buffer))
using(var writer = new WaveFileWriter(new IgnoreDisposeStream(stream), new WaveFormat(44100, 1)))
{
var recorder = new WaveInEvent
{
WaveFormat = new WaveFormat(44100, 1),
BufferMilliseconds = 100
};
recorder.StartRecording();
while (true)
{
yield return buffer;
buffer = new byte[512];
stream.SetLength(0);
}
}
}
this doesn't work, please give me a hand on how to do it.
thanks

You need to understand a couple of things which you miss.
First of all, WaveInEvent will write the data from the microphone asynchronously. Here is a correct snippet for writing the data from the microphone to some stream:
var buffer = new byte[512];
var recorder = new WaveInEvent
{
WaveFormat = new WaveFormat(44100, 1),
BufferMilliseconds = 100
};
var stream = new MemoryStream(buffer);
var writer = new WaveFileWriter(new IgnoreDisposeStream(stream), recorder.WaveFormat);
recorder.DataAvailable += (source, eventArgs) =>
{
var data = eventArgs.Buffer;
var bytesRead = eventArgs.BytesRecorded;
//here is a place where data from the microphone will be available
//you can add your processing right here in case you don't need to record and save the data
writer.Write(data, 0, bytesRead);
};
waveIn.StartRecording();
There are multiple different ways on how to proceed with the data you receive, but I don't know your main goal, so it is hard to say what is better way you choose the processing.

Related

C# HttpClient Abruptly stops download

I have this C# Script that is supposed to download a zip archive from GitHub, unpack it and put it in a specific folder:
using (var client = new HttpClient())
{
var filePath = Path.GetFullPath("runtime");#"https://github.com/BlackBirdTV/tank/releases/latest/download/runtime.zip?raw=true";
ConsoleUtilities.UpdateProgress("Downloading Runtime...", 0);
var request = await client.GetStreamAsync(url);
var buffer = new byte[(int)bufferSize];
var totalBytesRead = 0;
int bytes = 0;
while ((bytes = await request.ReadAsync(buffer, 0, buffer.Length)) != 0)
{
totalBytesRead += bytes;
ConsoleUtilities.UpdateProgress($"Downloading Runtime... ({totalBytesRead} of {bufferSize} bytes read) ", (int)(totalBytesRead / bufferSize * 100));
}
}
Decompress(buffer, filePath);
When I now run this, the download starts and it seems like it finishes, yet at a sporadic place it just stops. Somehow, It downloads the bytes as my Console shows, but they are zeroed out. It seems like either my computer receives zeros (which I doubt) or the bytes don't get written to the buffer.
Weirdly enough, downloading the file over the browser works just fine.
Any help is greatly appreciated
As I state in the comments, your problem is that each iteration of your while loop is overwriting your buffer, and you are not accumulating the data anywhere. So your last iteration doesn't completely fill the buffer and all you're left with is whatever data you got in the last iteration.
You could fix that bug by storing the accumulated buffer somewhere, but a far better solution is to not fuss with buffers and such and just use the built-in CopyToAsync method of Stream:
using var client = new HttpClient();
using var stream = await client.GetStreamAsync("https://github.com/BlackBirdTV/tank/releases/latest/download/runtime.zip?raw=true");
using var file = new FileStream(#"c:\temp\runtime.zip", FileMode.Create);
await stream.CopyToAsync(file);
Here I'm saving it to a local file at c:\temp\runtime.zip, but obviously change that to suit your needs. I suppose you're avoiding this method so you can track progress, which is fair enough. So if that's really important to you, read on for a fix to your original solution.
For completeness, here's your original code fixed up to work by writing the buffer to a FileStream:
var bufferSize = 1024 * 10;
var url = #"https://github.com/BlackBirdTV/tank/releases/latest/download/runtime.zip?raw=true";
using var client = new HttpClient();
using var stream = await client.GetStreamAsync(url);
using var file = new FileStream(#"c:\temp\runtime.zip", FileMode.Create);
var filePath = Path.GetFullPath("runtime");
var request = await client.GetStreamAsync(url);
var buffer = new byte[(int)bufferSize];
var totalBytesRead = 0;
int bytes = 0;
while ((bytes = await request.ReadAsync(buffer, 0, buffer.Length)) != 0)
{
await file.WriteAsync(buffer, 0, bytes);
totalBytesRead += bytes;
ConsoleUtilities.UpdateProgress($"Downloading Runtime... ({totalBytesRead} of {bufferSize} bytes read) ", (int)(totalBytesRead / bufferSize * 100));
}

Transfer real time live audio From microphone over TCP/IP Using C# .net

I want to make an app to transfer Audio from the microphone in a laptop or PC live, in real time, like a YouTube stream but without video. I will describe my process:
I transfer a normal file by converting it to byte then back again to origin.
I change the file type to MP3 or wav then use NAudio. Works fine also I can play the file if transferred or while receiving
I change the input file to Microphone and receive the audio.
Here is the problem: NAudio is unable to put the live stream from the mic then send it automatically. Always, the buffer gives me a null pointer exception while debugging ,then it gives me another error that the decoder of NAudio did not receive any data, "not acceptable by the way".
It should listen or keep receiving data until the port or connection closes.
I've tried to search about any library about VoIP but found nothing except Ozeki, but no tutorial to handle. All I found is old videos that do not work. I searched about that over a week but no result. I don't want a fully developed project because I already found one, but it is too complex -- about 2K lines of code. All I need is to know what to do or to be given the code that solves the problem.
This is client side code:
public void client()
{
try
{
//byte[] send_data = Audio_to_byte(); // ORIGINAL WORK CODE
byte[] send_data = new byte [BufferSize]; // 100M buffer size
TcpClient client = new TcpClient(serverip, port);
NetworkStream stream = client.GetStream();
// sourceStream and wavein is global vars
sourceStream = new NAudio.Wave.WaveIn();
sourceStream.DeviceNumber = 1;
sourceStream.WaveFormat = new NAudio.Wave.WaveFormat(44100, NAudio.Wave.WaveIn.GetCapabilities(1).Channels);
wavein = new NAudio.Wave.WaveInProvider(sourceStream);
//wavein.Read(send_data, 0, send_data.Length); // this buffer not work some times give me full buffer
BufferedWaveProvider pro = new BufferedWaveProvider(wavein.WaveFormat);
pro.AddSamples(send_data, 0, send_data.Length); // Empty buffer or error full buffer
stream.Write(send_data, 0, send_data.Length);
stream.Close();
client.Close();
}
catch (Exception e)
{
MessageBox.Show("Server is offline" + e, "Error");
// Here the message is buffer is full or send it empty then the decoder did not receive anything give exception error or of them happen first
}
}
and this server side code with MP3 reader code
IPAddress ip = Dns.GetHostEntry(serverip).AddressList[0];
TcpListener server_obj = new TcpListener(ip,port);
TcpClient client = default(TcpClient);
try
{
server_obj.Start();
while (true)
{
// accept all client
client = server_obj.AcceptTcpClient();
// make byte storage from network
byte[] received_buffer = new byte[BufferSize];
//get data from cst
NetworkStream stream = client.GetStream();
//save data from network to memory till finish then save with playing
MemoryStream ms = new MemoryStream();
int numBytesRead = 0;
while ((numBytesRead = stream.Read(received_buffer, 0, received_buffer.Length)) > 0)
{
// THIS STEP TO RECEIVE ALL DATA FROM CLIENT
ms.Write(received_buffer, 0, numBytesRead);
//receive sound then play it direct
WaveOut(ms.ToArray());
}
Byte_to_audio(ms.ToArray()); // YOU can make or allow override
}
}
catch(Exception e)
{
MessageBox.Show("Error Message : " + e, "Error");
}
}
this is Method that read stream receiving data from network
private void WaveOut(byte[] mp3Bytes)
{
// MP3 Format
mp3Stream = new MemoryStream(mp3Bytes);
mp3FileReader = new Mp3FileReader(mp3Stream);
wave32 = new WaveChannel32(mp3FileReader, 0.3f, 3f);
ds = new DirectSoundOut(); // but declration up global
ds.Init(wave32);
ds.Play(); // work code*/
}
I recommend using UDP, if it has to be in real time.
As I use Naudio with vb.net, I based this post.
Client Example:
waveIn = new WaveIn();
waveIn.BufferMilliseconds = 50; //Milissecondes Buffer
waveIn.DeviceNumber = inputDeviceNumber;
waveIn.WaveFormat = HEREWaveFormatHERE;
waveIn.DataAvailable += waveIn_DataAvailable; //Event to receive Buffer
waveIn.StartRecording();
void waveIn_DataAvailable(object sender, WaveInEventArgs e)
{
//e -> BUFFER
stream.Write(send_data, 0, send_data.Length);
stream.Close();
client.Close();
}
RECEIVE:
1 - Create WaveOut and BufferProvider Global
WOut = New WaveOut(WaveCallbackInfo.FunctionCallback());
BufferedWaveProvider pro = new BufferedWaveProvider(HEREWaveFormatHERE);
pro.BufferLength = 20 * 1024; //Max Size BufferedWaveProvider
pro.DiscardOnBufferOverflow = True;
WOut.Init(pro);
WOut.Play();
As long as there is no audio BufferedWaveProvider will provide silence for WaveOut or other outputs, it will also queue everything that arrives, for continuous playback.
2 - Play and Enqueue
while ((numBytesRead = stream.Read(received_buffer, 0, received_buffer.Length)) > 0)
{
pro.AddSamples(received_buffer, 0, numBytesRead);
}
My knowledge of naudio is limited to that
English from google translator

C#: Download large sized json file from ADLS gen2 blob and Deserialize to object

I am using following code to output data from blob to stream.:
private static async Task<Stream> ParallelDownloadBlobAsync(Stream outPutStream, CloudBlockBlob blob)
{
await blob.FetchAttributesAsync();
int bufferLength = 1 * 1024 * 1024;//1 MB chunk
long blobRemainingLength = blob.Properties.Length;
Queue<KeyValuePair<long, long>> queues = new Queue<KeyValuePair<long, long>>();
long offset = 0;
while (blobRemainingLength > 0)
{
long chunkLength = (long)Math.Min(bufferLength, blobRemainingLength);
queues.Enqueue(new KeyValuePair<long, long>(offset, chunkLength));
offset += chunkLength;
blobRemainingLength -= chunkLength;
}
Parallel.ForEach(queues, new ParallelOptions()
{
//Gets or sets the maximum number of concurrent tasks
MaxDegreeOfParallelism = 10
}, (queue) =>
{
using (var ms = new MemoryStream())
{
blob.DownloadRangeToStreamAsync(ms, queue.Key, queue.Value);
lock (outPutStream)
{
outPutStream.Position = queue.Key;
var bytes = ms.ToArray();
outPutStream.Write(bytes, 0, bytes.Length);
}
}
});
return outPutStream;
}
Then i have used JsonSerializer to deseriize data but while block is not executing
await ParallelDownloadBlobAsync(stream, cloudBlockBlob);
//resetting stream's position to 0
//stream.Position = 0;
var serializer = new JsonSerializer();
using (var sr = new StreamReader(stream))
{
using (var jsonTextReader = new JsonTextReader(sr))
{
jsonTextReader.SupportMultipleContent = true;
result = new List<T>();
while (jsonTextReader.Read())
{
result.Add(serializer.Deserialize<T>(jsonTextReader));
}
}
}
If i use DownloadToStreamAsync instead of parallel download (DownloadRangeToStreamAsync) then
it works.
I can repro your issue, and the solution here is that in the ParallelDownloadBlobAsync method, change this line of code blob.DownloadRangeToStreamAsync(ms, queue.Key, queue.Value); to blob.DownloadRangeToStream(ms, queue.Key, queue.Value);
Not sure if the same root cause of the issue for you and me. In my side, the root cause is that when the file is small(like 100kb), when using blob.DownloadRangeToStreamAsync method, the output stream is always 0, so the while condition is never executed. But for larger files, it's ok to use blob.DownloadRangeToStreamAsync method.
Please leave a comment if it cannot resolve your issue.

How to write NAudio WaveStream to a Memory Stream?

I have a program that takes in mp3 data in a byte array. It has to convert that mp3 data into wav format and store it in a byte data. I am trying to use NAudio for this purpose. I am using the following code for this purpose.
Stream inputStream = ...;
Stream outputStream = ...;
using (WaveStream waveStream = WaveFormatConversionStream.CreatePcmStream(new Mp3FileReader(inputStream)))
using (WaveFileWriter waveFileWriter = new WaveFileWriter(outputStream, waveStream.WaveFormat))
{
byte[] bytes = new byte[waveStream.Length];
waveStream.Read(bytes, 0, waveStream.Length);
waveFileWriter.WriteData(bytes, 0, bytes.Length);
waveFileWriter.Flush();
}
When I run the above code, all I receive is 0 in the byte array. But if use WaveFileWriter to write the data directly to a file, the file receives the correct data. Any reasons?
Give this a try:
using (WaveStream waveStream = WaveFormatConversionStream.CreatePcmStream(new Mp3FileReader(inputStream)))
using (WaveFileWriter waveFileWriter = new WaveFileWriter(outputStream, waveStream.WaveFormat))
{
byte[] bytes = new byte[waveStream.Length];
waveStream.Position = 0;
waveStream.Read(bytes, 0, waveStream.Length);
waveFileWriter.WriteData(bytes, 0, bytes.Length);
waveFileWriter.Flush();
}
If you are writing to a MemoryStream, you need to be aware that WaveFileWriter will dispose that MemoryStream after you dispose the WaveFileWriter.
Here's a workaround using the IgnoreDisposeStream. (Also note that WaveFormatConversionStream.CreatePcmStream is unnecessary - Mp3FileReader already returns PCM from Read). I also prefer to read in smaller chunks that trying to pass through the whole file.
var path = #"mytestFile.mp3";
var mp3ByteArray = File.ReadAllBytes(path);
var outputStream = new MemoryStream();
using (var mp3Stream = new MemoryStream(mp3ByteArray))
using (var reader = new Mp3FileReader(mp3Stream))
using (var waveFileWriter = new WaveFileWriter(new IgnoreDisposeStream(outputStream),
reader.WaveFormat))
{
byte[] buffer = new byte[reader.WaveFormat.AverageBytesPerSecond];
int read;
while((read = reader.Read(buffer,0, buffer.Length)) > 0)
{
waveFileWriter.Write(buffer, 0, read);
}
}
// outputStream has not yet been disposed so we can get the byte array from it
var wavBytes = outputStream.GetBuffer();
// or we could play it like this
outputStream.Position = 0;
using (var player = new WaveOutEvent())
using (var reader = new WaveFileReader(outputStream))
{
player.Init(reader);
player.Play();
while(player.PlaybackState != PlaybackState.Stopped)
{
Thread.Sleep(1000);
}
}

Concatenating SoundEffects (wav) and saving to isolated storage

I am having an awful time trying to come up with a good solution to this problem of mine.
I have 3 sound effects that are marked as content on the phone, all the same bitrate.
sound1.wav
sound2.wav
sound3.wav
I want the user to be able to be able to select in any order, or however many times they like, the play order of the wav files, and then generate a new wav file based on their choices which can be stored and brought back from isolated storage.
So Thank You Walt Ritscher with the help so far, but as you will eventually see my coding skills are fragmented at best. What I'm trying to convey in the following code is that a user will be prompted to select any/all of the sounds with a tap event, and his selections will determine what the new soundeffect will sound like (it's order, etc) However there is still a lot I don't know about and here is the code I came up with (while not on my coding computer);
//SO I have this master list of sounds to use, indicated in this block of code:
//sound1.wav, sound2.wav, sound3.wav
// my wav files are marked as resources
// get the wav file from the DLL
var streamInfo1 = Application.GetResourceStream(
new Uri(sound1.wav, UriKind.Relative));
var streamInfo2 = Application.GetResourceStream(
new Uri(sound2.wav, UriKind.Relative));
var streamInfo3 = Application.GetResourceStream(
new Uri(sound3.wav, UriKind.Relative));
//With the above declarations made, I run each one as a stream as a variable.
var stream1 = streamInfo1.Stream as UnmanagedMemoryStream;
var stream2 = streamInfo2.Stream as UnmanagedMemoryStream;
var stream3 = streamInfo3.Stream as UnmanagedMemoryStream;
//The user can choose the sounds in any order, and repeat if desired.
//Let us assume the user chose in this order:
//sound1.wav + sound1.wav + sound2.wav +sound3.wav
for (int i = 0; i < 10; i++)
{
var bytesA = new byte[stream1.Length];
var bytesB = new byte[stream1.Length];
var bytesC = new byte[stream2.Length];
}
// read the bytes from the stream into the array
stream1.Read(bytesA, 0, (int)stream1.Length);
stream2.Read(bytesB, 0, (int)stream1.Length);
stream3.Read(bytesC, 0, (int)stream2.Length);
var combined = new byte[bytesA.Length + bytesA.Length + bytesB.Length] + bytesC.Length]];
// copy the bytes into the combined array
System.Buffer.BlockCopy(bytesA, 0, combined, 0, bytesA.Length);
System.Buffer.BlockCopy(bytesB, 0, combined, bytesA.Length, bytesB.Length);
var outputStream = new MemoryStream();
outputStream.Write(combined, 0, combined.Length);
// substitute your own sample rate
var effect = new SoundEffect(
buffer: outputStream.ToArray(),
sampleRate: 48000,
channels: AudioChannels.Mono);
var instance = effect.CreateInstance();
instance.Play();
// save stream to IsolatedStorage
Basically you have to get the bytes from the stream and combine into a new byte array. Then store that array into an UnmanagedMemoryStream.
// my wav files are marked as resources
// get the wav file from the DLL
var streamInfo1 = Application.GetResourceStream(
new Uri(loopWav, UriKind.Relative));
var streamInfo2 = Application.GetResourceStream(
new Uri(beatWav, UriKind.Relative));
var stream1 = streamInfo1.Stream as UnmanagedMemoryStream;
var stream2 = streamInfo2.Stream as UnmanagedMemoryStream;
var bytesA = new byte[stream1.Length];
var bytesB = new byte[stream2.Length];
// read the bytes from the stream into the array
stream1.Read(bytesA, 0, (int)stream1.Length);
stream2.Read(bytesB, 0, (int)stream2.Length);
var combined = new byte[bytesA.Length + bytesB.Length];
// copy the bytes into the combined array
System.Buffer.BlockCopy(bytesA, 0, combined, 0, bytesA.Length);
System.Buffer.BlockCopy(bytesB, 0, combined, bytesA.Length, bytesB.Length);
var outputStream = new MemoryStream();
outputStream.Write(combined, 0, combined.Length);
// substitute your own sample rate
var effect = new SoundEffect(
buffer: outputStream.ToArray(),
sampleRate: 48000,
channels: AudioChannels.Mono);
var instance = effect.CreateInstance();
instance.Play();
// save stream to IsolatedStorage
I've written more about WP7 audio for CoDe Magazine.
http://www.code-magazine.com/Article.aspx?quickid=1109071

Categories

Resources