In my Silverlight application, I read audio data from a File with a ZipInputStream, then store it in a MemoryStream. Here's the code I'm using:
byte[] buf = new byte[1024];
MemoryStream memoryStream = new MemoryStream();
int len;
while ((len = zipInputStream.Read(buffer, 0, buffer.Length)) > 0)
{
memoryStream.Write(buf, 0, len);
}
// Reset the position for reading.
memoryStream.Position = 0;
// Check how large the byte[] is.
textBox.Text = memoryStream.ToArray().Length.ToString();
MediaElement me = new MediaElement();
me.setSource(memoryStream);
me.Play();
This code partly works; the song from the input file starts playing. In addition, the byte[] always has the same length for the same song. I take this to mean that the song is being completely read each time.
However, my problem is that the audio randomly stops playing at a different point each run through. The song has not yet fully played, either. I'm not exactly sure why this happens.
If anyone knows, I'd like to know why this is happening. I'd also like to know if there's something wrong with my code, or if there's a different way I should go about storing the audio (that doesn't involve storing a file on the user's computer).
I was finally able to find a solution. By making the MediaElement and MemoryStream global variables, the song played through completely each time. I'm still not 100% sure what caused this error, although my best guess is that the problem was caused by the garbage collector deleting the stream.
Related
If I did this in my MAUI project:
var uploadImage = new UploadImage();
var img = await uploadImage.OpenMediaPickerAsync();
var imagefile = await uploadImage.Upload(img);
var imageBytes = uploadImage.StringToByteBase64(imagefile.byteBase64);
var stream = uploadImage.ByteArrayToStream(imageBytes);
img_profilePic.Source = ImageSource.FromStream(() => stream); //working
I am displaying an image from my ios simulator. At one point in time I have the stream of the IO at my displosal.
If I now add
MemoryStream newStream = new MemoryStream();
stream.CopyTo(newStream);
these two lines of code to my code above, the image I was displaying at that point dissapears.
SO somehow, when I copy my stream, I for some reason also delete the already existing stream...?
What is going on here...
The point of streams is to be able to process very large amounts of data (sequentially) without having to load all that data into memory (at once anyway), which is what happens if instead of streams you work with collections. So, what stream do is track the current position so they can keep loading more data to memory when the position moves forward and unload already processed data. So, using the same stream for two things it's not going to work because the second usage won't get the data that the first usage has already consumed.
That said, it's possible to reset the position of a stream with the seek operation (as long as the type of stream you are using allows it).
Check out this answer https://stackoverflow.com/a/1746108/352826
SO somehow, when I copy my stream, I for some reason also delete the already existing stream...?
It's far more likely that you're trying to use the same stream as multiple sources without rewinding it. Streams have a position that increases as you use it.
In short, use this when you want to reuse your stream:
stream.Position = 0;
Assuming, of course, that whatever stream you're using is rewindable in the first place. If not, then copy it to a memory stream first and reuse that as many times as you wish, rewinding between uses.
I receive a fair amount of binary data from an external device, about 30-40 MB/s. I need to save it to a file. On the external source device side, I have a very small buffer that I can't enlarge and as soon as the transmission stutters on the C# application side, it quickly gets clogged and I lose data.
In the application, I tried writing using FileStream, but unfortunately it is not fast enough.
_FileStream = new FileStream(FileName, FileMode.Create, FileAccess.Write);
...
void Handler_OnFtdiBytesReceived(object sender, FtdiBytesReceivedEventArgs e)
{
...
Array.Copy(e.Bytes, 0, _ReceivedDataBuffer, _ReceivedDataBufferPosition, e.NumBytesAvailable);
_ReceivedDataBufferPosition += (int)e.NumBytesAvailable;
if (_ReceivedDataBufferPosition > 0)
{
_FileStream.Write(_ReceivedDataBuffer, 0, (int)e.NumBytesAvailable);
_ReceivedDataBufferPosition = 0;
}
if (_IsOperationFinished == true)
{
_FileStream.Flush();
_FileStream.Close();
}
...
}
I also tried adding a BinaryWriter:
_FileStream = new FileStream(FileName, FileMode.Create, FileAccess.Write);
_BinaryWriter = new BinaryWriter(_FileStream);
and then:
_BinaryWriter.Write(_ReceivedDataBuffer, 0, (int)e.NumBytesAvailable);
instead of previous _FileStream.Write(...), but also the buffer on the transmit side gets clogged.
Is there any way to deal with this?
I wonder if it might help to somehow buffer the data in the computer's RAM when receiving it and, for example, when it reaches some sizable amount (say, 512 MB), start writing to the file in a separate Task, so that in the meantime, new data can be collected into the buffer continuously. Perhaps I would need to use two buffers and use them alternately, one to receive data continuously and the other from which to write to the file, and swap??
This seems quite complex code for someone with little experience, which I don't know if it will help, so I'd like to ask you for a hint first.
I'll just add at the end that I have the ability to watch the buffer fill up in this external device and by commenting out this one line regarding writing:
_FileStream.Write(_ReceivedDataBuffer, 0, (int)e.NumBytesAvailable);
I see that the problem with its clogging disappears. Earlier I also analyzed whether other code fragments might be inefficient, such as Array.Copy(...) or passing parameters via Event, but it had no effect.
I am trying to increase the amplitude of the sound wave in my code. I have the buffer consisting of all the bytes needed to make the wave.
Here is my code for the audio Playback:
public void AddSamples(byte[] buffer)
{
//somehow adjust the buffer to make the sound louder
bufferedWaveProvider.AddSamples(buffer, 0, buffer.Length);
WaveOut waveout = new WaveOut();
waveout.Init(bufferedWaveProvider);
waveout.Play();
//to make the program more memory efficient
bufferedWaveProvider.ClearBuffer();
}
You could convert to an ISampleProvider and then try to amplify the signal by passing it through a VolumeSampleProvider with a gain > 1.0. However, you could end up with hard clipping if any samples go above 0.
WaveOut waveout = new WaveOut();
var volumeSampleProvider = new VolumeSampleProvider(bufferedWaveProvider.ToSampleProvider());
volumeSampleProvider.Volume = 2.0f; // double the amplitude of every sample - may go above 0dB
waveout.Init(volumeSampleProvider);
waveout.Play();
A better solution would be to use a dynamic range compressor effect, but NAudio does not come with one out of the box.
I had a similar problem, too. But Could done with it with this link:
http://mark-dot-net.blogspot.hu/2009/10/playback-of-sine-wave-in-naudio.html
If you know all details about your sound It would be helpful I think
I am trying to load some filestream into a memorystream. The source stream could be any stram, but the focus here is the destination stream.
The source has more than 3Gb.
I tryed 4 different approaches to this.
1)fDest = new MemoryStream(); and then read 4K blocks into this. This takes forever com complete as the buffer must be resized on every step.
2)fDest = new MemoryStream(int.MaxValue); Got OutOfMemoryException on creation
3)fDest = new MemoryStream(1073741823); and then read 4K blocks into this. This loads fast but i get an OutOfMemory exception when the buffer needs to be resized.
4)fDest = new MemoryStream(1073741824);and then read 4K blocks into this. This works. The buffer resize is ok.
Can anyone point me some direction on why i got this behaviour with just one byte in diference on buffer size? I
I've been playing around with what I thought was a simple idea. I want to be able to read in a file from somewhere (website, filesystem, ftp), perform some operations on it (compress, encrypt, etc.) and then save it somewhere (somewhere may be a filesystem, ftp, or whatever). It's a basic pipeline design. What I would like to do is to read in the file and put it onto a MemoryStream, then perform the operations on the data in the MemoryStream, and then save that data in the MemoryStream somewhere. I was thinking I could use the same Stream to do this but run into a couple of problems:
Everytime I use a StreamWriter or StreamReader I need to close it and that closes the stream so that I cannot use it anymore. That seems like there must be some way to get around that.
Some of these files may be big and so I may run out of memory if I try to read the whole thing in at once.
I was hoping to be able to spin up each of the steps as separate threads and have the compression step begin as soon as there is data on the stream, and then as soon as the compression has some compressed data available on the stream I could start saving it (for example). Is anything like this easily possible with the C# Streams? ANyone have thoughts as to how to accomplish this best?
Thanks,
Mike
Using a helper method to drive the streaming:
static public void StreamCopy(Stream source, Stream target)
{
byte[] buffer = new byte[8 * 1024];
int size;
do
{
size = source.Read(buffer, 0, 8 * 1024);
target.Write(buffer, 0, size);
} while (size > 0);
}
You can easily combine whatever you need:
using (FileStream iFile = new FileStream(...))
using (FileStream oFile = new FileStream(...))
using (DeflateStream oZip = new DeflateStream(outFile, CompressionMode.Compress))
StreamCopy(iFile, oZip);
Depending on what you are actually trying to do, you'd chain the streams differently. This also uses relatively little memory, because only the data being operated upon is in memory.
StreamReader/StreamWriter shouldn't have been designed to close their underlying stream -- that's a horrible misfeature in the BCL. But they do, they won't be changed (because of backward compatibility), so we're stuck with this disaster of an API.
But there are some well-established workarounds, if you want to use StreamReader/Writer but keep the Stream open afterward.
For a StreamReader: don't Dispose the StreamReader. It's that simple. It's harmless to just let a StreamReader go without ever calling Dispose. The only effect is that your Stream won't get prematurely closed, which is actually a plus.
For a StreamWriter: there may be buffered data, so you can't get away with just letting it go. You have to call Flush, to make sure that buffered data gets written out to the Stream. Then you can just let the StreamWriter go. (Basically, you put a Flush where you normally would have put a Dispose.)
Unless you're reading in streams bigger than your hard drive, I don't think you'll run out of memory:
http://blogs.msdn.com/ericlippert/archive/2009/06/08/out-of-memory-does-not-refer-to-physical-memory.aspx