0

I am building a small morse code app. I have the "Dash.mp3" and "Dot.mp3" on my computer and I am parsing it into bytes. I then take the bytes and "build" the sound based on the input. example:

"SOS" = ... --- ... . = "dot.mp3" = bytes = [10,20] (example).

  • = "dash.mp3" = bytes = [30,40] (example). so the end output in bytes would be :

[10,20,10,20,10,20,30,40,30,40,30,40,10,20,10,20,10,20]

I then send these bytes as A stream in response to the AJAX call.

it seems like when the input is short like "SOS" it works, but when it gets longer like "SOSSS" it freezes. no idea why. hope someone could help me/ suggest maybe a different approach to building the sounds.

AJAX:

$(function () {
    var q = $.QueryString["msg"];
    $.ajax({
        type: "POST",
        url: "/morse",
        dataType: 'JSON',  
        data: q,
        success: function (data) {
            console.log("yay");
        },
        error: function (req, status, error) {
            console.log("nay");
        }
    });
});

Controller action:

[Route("morse")]
    public async Task<ActionResult<byte[]>> Morse(string msg)
    {

        var sound = await Task.FromResult(_decoder.MorseBuilder(msg));
        MemoryStream stream = new MemoryStream(sound);
        return File(stream, "audio/mp3");
    }

The morse builder class:

 public class MorseDecoder : IMorseDecoder
    {
        readonly byte[] dot;
        readonly byte[] dash;
        public MorseDecoder()
        {
            dot = System.IO.File.ReadAllBytes("C:\\Users\\Feuse135\\source\\repos\\MorseCodeServer\\wwwroot\\audio\\dot.mp3");
            dash = System.IO.File.ReadAllBytes("C:\\Users\\Feuse135\\source\\repos\\MorseCodeServer\\wwwroot\\audio\\dash.mp3");
        }
     

        public byte[] MorseBuilder(string msg)
        {
           
            var decoded = Decode(msg); // turns string into morse (..-.-.-)

            List<byte> sound = new List<byte>();
            foreach (var letter in decoded)
            {
                switch (letter)
                {
                    case '.':
                        foreach (var item in dot)
                        {
                            sound.Add(item);
                        }
                        break;

                    case '-':
                        foreach (var item in dash)
                        {
                            sound.Add(item);
                        }
                        break;
                    default:
                        break;
                }  
            }

            return sound.ToArray();
        }
    }

EDIT UPDATE:

I made it so I download the file after finishing the bytes build and seeing if its corrupts, the .mp3 file works perfectly even with "SSSSSSSSSSSSSSSSSSSSS" it seems that the problem starts when I return the file back to the view...maybe there is some MAX capacity on response?

[Route("morse")] public ActionResult Morse(string msg) {

    var sound = _decoder.MorseBuilder(msg);

    System.IO.File.WriteAllBytes("C:\\Users\\Feuse135\\source\\repos\\MorseCodeServer\\wwwroot\\audio\\somefile.mp3", sound);
    var f = System.IO.File.ReadAllBytes("C:\\Users\\Feuse135\\source\\repos\\MorseCodeServer\\wwwroot\\audio\\somefile.mp3");
    return File(f, "audio/mpeg");
}
Roman Sterlin
  • 1,485
  • 3
  • 10
  • 25
  • `SOSSS` is not too long, have you tried debugging step by step yet? at least you can see where the freezing starts. – King King Feb 28 '21 at 18:16
  • the `foreach` in each `case` is surely not efficient, consider using the `List.AddRange` method instead, which should be more efficient than your own `foreach`. BTW, this looks like a performance issue related to just the `MorseBuilder` method, you should share your info about the time it takes to complete from start to end. Basing on `List` is easy but not efficient enough (the `AddRange` method should be the most efficient way of adding that you can try). Here we surely know the sizes (counts) beforehand so there will be a faster algorithm by implementing your own (not based on `List`) – King King Feb 28 '21 at 18:24
  • I made it so I download the file after finishing the bytes build and seeing if its corrupts, the .mp3 file works perfectly even with "SSSSSSSSSSSSSSSSSSSSS" it seems that the problem starts when I return the file back to the view...maybe there is some MAX capacity on response? – Roman Sterlin Feb 28 '21 at 18:30
  • Finally, if you can accept some kind of interruption between sounds (like playing continuous sound files), you can just return the morse code sequence, let the client cache 2 sound files (of `dot` and `dash`), and play each of them in sequence when reading the morse code (of course on the client side). That way it should be very fast on the server side, but the client side may have to accept some delay (of loading & playing each file), as long as the sound file is good and you test it, it should be acceptable. – King King Feb 28 '21 at 18:31
  • I don't think there is any max response size. It depends on how your client (browser) handles the response (e.g: printing a large response to the console may cause freezing, ...). – King King Feb 28 '21 at 18:33
  • interesting... no, there is no console logs or anything, simply an ajax call to the controller, controller responds with the file and AJAX isn't even getting to success/ error part cuz browser just redirects everything to a mp3 player that plays the sound... when uploading a big song, it works. when doing "SSS" it works. when doing "SSSSSS" it won't work. but the "SSSSSSS" file that its saving to my pc is good and I hear everything as it should...so weird. – Roman Sterlin Feb 28 '21 at 18:38
  • I may just end up playing the sounds on the client side like you said..I did that earlier but I wanted the sound to come from the server...oh well! thanks for trying. – Roman Sterlin Feb 28 '21 at 18:39

1 Answers1

0

Turns out MP3 files have something called headers and by trying to concat sounds together using their bytes I broke them.

more about MP3 headers : http://www.mp3-tech.org/programmer/frame_header.html

and this answer helped me : C# : concatenate 2 MP3 files

I used his code but instead of concatenating two separate MP3 files I just go one by because it fits my needs.

 public void Combine(string file, Stream output)
    {

        Mp3FileReader reader = new Mp3FileReader(file);

        if ((output.Position == 0) && (reader.Id3v2Tag != null))
        {
            output.Write(reader.Id3v2Tag.RawData, 0, reader.Id3v2Tag.RawData.Length);
        }
        Mp3Frame frame;
        while ((frame = reader.ReadNextFrame()) != null)
        {
            output.Write(frame.RawData, 0, frame.RawData.Length);
        }
    }

How I use it :

 MemoryStream st = new MemoryStream();
  Combine("dot.mp3", st);
  Combine("dash.mp3", st);
  Combine("dot.mp3", st);

then you just use the stream however you want.

Roman Sterlin
  • 1,485
  • 3
  • 10
  • 25
  • so this is also the cause for freezing on the client-side? so actually the client-side player does not handle it well. Still it's strange you commented that the result file (generated by the original code) can play well (by opening the file by some desktop player). – King King Mar 01 '21 at 16:35
  • the ones that played were just luck. none of them should work because of the way I concatenated them. in order for you to combine two mp3 files together you have to add the headers also, not sure exactly how it works I just know now that it wont work if you just try to combine the bytes. – Roman Sterlin Mar 01 '21 at 16:43