-2

I have:

Stereo [] noteBuffer = new noteBuffer[ 128 ];

{ ... fill it.... }

where:

public class Stereo
{
    public int Samples;
    public float [] L,R;

    public Stereo( int N )
    {
        Samples = N;
        L = new float[ N ];
        R = new float[ N ];
    }   
}

How can I { save to disk } / { load from disk }?

(NOTE: different notes will have different length buffers)

halfer
  • 19,824
  • 17
  • 99
  • 186
P i
  • 29,020
  • 36
  • 159
  • 267
  • I think, the reason for downvotes is clear. Internet is full of topics about serialization and different serializers. You should make your own homework and make some research before asking a question. – EZI Dec 08 '13 at 20:53
  • Yes the Internet is full of information, and this has been the difficulty: finding which out of the many possible solutions is the most sensible for this particular situation. Best answered by someone with experience in the field (thanks Scott). I shouldn't have to obfuscate a clear, direct question with my own 'homework' and 'research' just to prove that I'm not being lazy. – P i Dec 09 '13 at 01:06

4 Answers4

2

You can always use Protobuf is very very fast.

See http://code.google.com/p/protobuf-net/wiki/Performance for in depth information concerning the performance of this system, and an implementation.

But if you want a more standard and Cross-platform way to do it, here is my answer(I don't think that for 30 mb will cause an issue )

 public void test()
    {
        Stereo [] noteBuffer = new noteBuffer[ 128 ];
       SerializeToXml<List<Stereo>>(noteBuffer.ToList(), outfile);
    }



    public static T DeserializeFromXml<T>(string inputFile)
    {
        XmlSerializer s = new XmlSerializer(typeof(T));
        T deserializedObject = default(T);

        using (TextReader textReader = new StreamReader(inputFile))
        {
            deserializedObject = (T)s.Deserialize(textReader);
            textReader.Close();
        }

        return deserializedObject;
    }

    public static void SerializeToXml<T>(T objToSerialize, string outputFile)
    {

        XmlSerializer s = new XmlSerializer(objToSerialize.GetType());

        using (TextWriter textWriter = new StreamWriter(outputFile))
        {
            s.Serialize(textWriter, objToSerialize);
            textWriter.Close();
        }
    }
BRAHIM Kamel
  • 13,492
  • 1
  • 36
  • 47
  • thanks for answer, but how (in)efficient is this re: space? (this may be ~30MB of raw floats) – P i Dec 08 '13 at 20:17
  • Being text based each channel of each sample of each sterieo in the array will grow at least "# of digits" in size so you are likely to be at least 100MB of text when you are done. – Scott Chamberlain Dec 08 '13 at 20:31
  • @ScottChamberlain please take a look at this link which is not true what's you are telling http://stackoverflow.com/questions/7964280/c-sharp-serialize-generic-listcustomobject-to-file – BRAHIM Kamel Dec 08 '13 at 20:38
  • @JulieShannon What in that post shows that what I said is not true? Using a XMLSerializer the accepted answer said to took `251 bytes` of data to encode `15 bytes` of information (1 byte for each of the 3 empty strings, 8 bytes for the `foo.bar` string and 4 bytes for the HashTable (the 3 elements + length)). That is pretty much exactly what I was taking about. – Scott Chamberlain Dec 08 '13 at 20:43
  • here are some reasons to don't use BinaryFormatter: many reasons; it has a habit of being version intolerant, it is not cross-platform (for example, useless even on Silverlight), it is slow, and it has overweight output. Even invisible changes like making something an automatically implemented property will break it. Oh, and it tends to suck in unwanted objects via events – BRAHIM Kamel Dec 08 '13 at 20:47
  • Yea, I agree with you, I don't recommend using `BinaryFormatter` for persistent storage. `BinaryFormatter` should only be used for serializing IPC using shared assemblies for the class definition. But I did not say use `BinaryFormatter`, I said using a text based serialization will explode the size. – Scott Chamberlain Dec 08 '13 at 20:48
  • I don't think now a day space required it's matter but performance yes – BRAHIM Kamel Dec 08 '13 at 20:50
1

With a class that simple I would just write a static function that can write Stereo arrays in to a stream and another to read them back out again.

internal class Program
{
    public static void Main()
    {
        Stereo[] stereos = FunctionThatCreatesTheArray();

        using (var writeStream = File.OpenWrite(@"C:\Example\MultiChannelSong.bin"))
        {
            Stereo.Serialize(stereos, writeStream);
        }

        Stereo[] newStereos;
        using (var readStream = File.OpenRead(@"C:\Example\MultiChannelSong.bin"))
        {
           newStereos = Stereo.Deseralize(readStream);
        }

    }
}

public class Stereo
{
    public int Samples;
    public float[] L, R;

    public Stereo(int N)
    {
        Samples = N;
        L = new float[N];
        R = new float[N];
    }

    public static void Serialize(Stereo[] stereos, Stream destination)
    {
        using (BinaryWriter writer = new BinaryWriter(destination, Encoding.Default, true))
        {
            //Write the size of the array to the file
            writer.Write(stereos.LongLength);
            foreach (Stereo stereo in stereos)
            {
                //Write the number of samples there are
                writer.Write(stereo.Samples);

                //Write out the L channel
                foreach (var l in stereo.L)
                {
                    writer.Write(l);
                }

                //Write out the R channel
                foreach (var r in stereo.R)
                {
                    writer.Write(r);
                }
            }
        }
    }

    public static Stereo[] Deseralize(Stream source)
    {
        using (BinaryReader reader = new BinaryReader(source, Encoding.Default, true))
        {
            //Read in the number of records
            var records = reader.ReadInt64();
            Stereo[] stereos = new Stereo[records];

            for (long i = 0; i < records; i++)
            {
                //Read in the number of samples
                var samples = reader.ReadInt32();
                var stereo = new Stereo(samples);

                //Read in the L channel
                for (int j = 0; j < samples; j++)
                {
                    stereo.L[j] = reader.ReadSingle();
                }

                //Read in the R channel
                for (int j = 0; j < samples; j++)
                {
                    stereo.R[j] = reader.ReadSingle();
                }

                //Set the sterieo object we created in to the array.
                stereos[i] = stereo;
            }
            return stereos;
        }
    }
}

If you want to be fancy you could compress the output and input too to help save space.

public static void Serialize(Stereo[] stereos, Stream destination)
{
    using (GZipStream compressionStream = new GZipStream(destination, CompressionMode.Compress, true))
    using (BinaryWriter writer = new BinaryWriter(compressionStream, Encoding.Default, true))
    {
        //No changes here required
    }
}

public static Stereo[] Deseralize(Stream source)
{
    using (GZipStream decompressionStream = new GZipStream(source, CompressionMode.Decompress, true))
    using (BinaryReader reader = new BinaryReader(decompressionStream, Encoding.Default, true))
    {
        //No changes here required
    }
}
Scott Chamberlain
  • 124,994
  • 33
  • 282
  • 431
  • Thanks, that's a great answer and a great help! Is there some speed inefficiency in reading/writing one single at a time as opposed to block r/w? – P i Dec 08 '13 at 20:30
  • 1
    Nah, just trust the underlying Stream to write out using the correct buffers. In my "example program" I may only write out one `short` at a time but the underlying `FileStream` has a internal buffer of `4096` bytes by default and only writes out to disk when it feels the buffer has gotten full enough (or someone calls a explicit `Stream.Flush()` on the stream). If you find that the 4K default buffer is too small [use a constructor of `FileStream` that allows you to set the buffer size manually](http://msdn.microsoft.com/en-us/library/f20d7x6t%28v=vs.110%29.aspx). – Scott Chamberlain Dec 08 '13 at 20:34
  • here are some reasons to don't use BinaryFormatter: many reasons; it has a habit of being version intolerant, it is not cross-platform (for example, useless even on Silverlight), it is slow, and it has overweight output. Even invisible changes like making something an automatically implemented property will break it. Oh, and it tends to suck in unwanted objects via events – BRAHIM Kamel Dec 08 '13 at 20:48
  • @JulieShannon please re-read my question more carefully, I am not using `BinaryFormatter` I am using `BinaryWriter` which is a very different class. I don't recommend using `BinaryFormatter` for persistent storage. `BinaryFormatter` should only be used for serializing IPC using shared assemblies for the class definition. Of your criticisms the ***only*** one that is applicable to my solution is that it is version intolerant. However that is why my first sentence was "*With a class that simple*", if this was a more complex format that could change I would use a library like protobuf instead. – Scott Chamberlain Dec 08 '13 at 20:52
  • Binary writer will make the task of serialization and deserialization more complex – BRAHIM Kamel Dec 08 '13 at 20:57
  • Did you read my answer, I have a fully working solution using `BinaryWriter` What about it is "too complex" for you. I agree that as class complexity goes up manually writing serialization grows quickly. However, for the third time: With a class this simple it is easier to hand do your own serialization than dealing with libraries, different problems require different solutions and a complex class that contain non simple structures will require a more robust solution (like protobuf). – Scott Chamberlain Dec 08 '13 at 21:02
1

At least the following serialization techniques could be used:

The usage of XmlSerializer could be found in this answer, XmlSerializer here

The analysis of effectiveness was provided in this answer

Community
  • 1
  • 1
Vadim Gremyachev
  • 57,952
  • 20
  • 129
  • 193
0

I usually use Json.NET for that. See: http://james.newtonking.com/archive/2009/02/14/writing-json-to-a-file-using-json-net

While it is not as space effective as the BinaryFormatter, it is miles better in terms of changing the object's signature.

Mark PM
  • 2,909
  • 14
  • 19