Melody Glider - My FEZ Cobra project

Hi,

I would like to share with you my program which I’m working on since about one month.
During summer practice I am learning C# and .NET Micro Framework with FEZ and I find it great.
While doing one application before, somebody told me to write an easter egg that will play a predefined melody. After that I thought that it would look better If i didn’t write 16 times “Utility.Piezoblahblah”, and so it has begun… I thought that it might be nice to make and upload a library which allows you to play custom melodies.
At the same time my supervisor told me about GHI Glide library so I started to learn how to use it.

My intention is to make good-looking, fast and easy to use application that allows you to create melodies for example when you know the music sheet but you don’t know how to read it.
Later it would be nice to have a simple sequencer+tracker for making old-PC-games-like music and to be able to attach this library to any project which is related to a device with buzzer, to make something nice with it, at least easter egg :).

The application is still to be improved, for sometimes I have forgot about thinking small, also maybe there will be possibility to speed up GUI.
Maybe some of you will have fun, maybe some of you could give me advices how to make my project better, maybe Glide-related people from GHI will see with this example what can they add/change in next releases of Glide. I’m open to criticism ;).

http://melodyglider.codeplex.com/

Regards,
Tomasz

Edit: Small bug, null reference exception when attempting to raise or lower sharp/flat note pitch (“up”/“down” button in the editor window). I have noticed this few minutes ago and solved it. Sorry for that. After doing few improvements/fixes more I will upload next version.

Do you have a teaser video to show? :slight_smile:

Hi,

Unfortunately not :(. But tomorrow I will make it (in US it will be about 3 AM ;)).

Regards,
Tomasz

Great application! I’m looking into your application to see if enhancements can be made.

I will be up till 3AM just to see the video :slight_smile:

That is a very cool example! thanks for sharing. Hopefully once i get up to speed on all of this i can create things like this as well. Its a good example for me to help me learn things for the LCD.

I have programming embedded C for so long my brain is fighting tooth and nail not to comprehend the C# OOP methodology. Its that or i am just getting to dam old for anything new :wink:

[quote] Its that or i am just getting to dam old for anything new
[/quote]

I don’t think it is age related. :wink:

From my experience (with others), it is very difficult for a very experienced C programmer to get started into object oriented programming. It almost requires a religious change.

The key to “conversion” is to relax. It will take a while. Reading good examples in the best way to start. Find a tutorial on OOP on the net. After a short time it will "click: into place. Think of OOP as building software components/chips.

If there are concepts you are having difficulty with post your questions. We are here to help.

BTW: To prove age is not an issue, I have underwear older than most of the people on this forum.

Josh,

Please notice, that I had a small problem with the melody content, especially with subscribing events to each added image and changing an image of specific selected note according to its duration. Then it turned out that there is something like HashTable ::). But then I wanted to decrease the number of duplicated sections of code everywhere, and after adding a few it might look a little messy… :confused:
As you could also see when selecting the note after cursor or vice versa, you can see every toggled button getting invalidated one by one. It will be better to invalidate window once after changing state of buttons to make it look better, and I think I’ll do so. But the main thing that is imo uncomfortably slow is the melody area (StaffDrawer). After deleting, cloning, pasting note or inc/dec pitch of it I can’t just (re)move part of the content and paste what is needed (because of different width of elements, because sometimes will get out of area etc), what would be faster… Also the scrolling has low performance because of that.
Well… While writing this post some solutions which maybe will work came to my mind.

Ah, there is a lot to talk about, it will be better if I’ll just come back tomorrow and upload a video and keep on coding ;).

Jdal,

I’m happy to help.
I was using C++ (but didn’t use it fully in OOP way), Matlab and a very little of C and assembly before… Now there are still some problematic issues for me using C# (for example how deep should I go with encapsulating code sections into methods), but it is so comfortable that I started to think that I’m writing an application for a PC :D. Now I have to revise my project in order to make it use less CPU and memory resources.
Getting to C# instead of C/C++ and maybe using VS with ReSharper helps you to focus on coding and to write what you have in your mind. The same thing, but according to electronics, is getting FEZ :).
Personally I like electronics a lot, for me it’s something like Lego bricks. Unfortunately I’m not very good in analog electronics (in spite of I’m studying faculty that consists of electronics ^^'). FEZ helps me understand a little bit more about electronics but mainly play with electronics without i.eg. writing my own drivers for everything connected (which maybe isn’t difficult, but may take a lot of time).
Also I have something commercial in mind and if I will start alone or with few friends, building complete devices will be fast and easy :wink: enough to cope with larger number of orders (I hope there will be any :D).

Regards,
Tomasz

I wish you well in your endeavors!!!
I just am so dam frustrated because i learned assembler and C very quickly. it came so natural for me.
People say assembler is hard but i disagree. Yet on the flip side i see the amazing things you all are doing in C# and i feel like a guy trying to learn french. Just is not clicking.

Your c/assembler skills will be very useful when you try RLP.

Tomasz3 why aren’t you using the built-in keyboard? I was curious to see what took so long with loading the name input window and its got 43 buttons!! Keep in mind that is 43 buttons doing scale9 at load. You can remove the NameInputWindow entirely and save a 4.4 seconds.

// Add to the top
using GHIElectronics.NETMF.Glide;

// Change the name box on tap
private void NameBoxTapEvent(object sender)
{
	//_gui.NameInputWindow.SetToMain();
	Glide.OpenKeyboard(sender);
}

You could probably also save some and make things look cleaner by not having an back image on every window. IMO only the splash window needs it.

Josh,

You’re right. The keyboard will be changed. I must figure out how to make custom keyboard. It may sound funny, but I made this before Glide version with keyboard customization was released. After this I thought that I may change the keyboard, but I was somehow tired of making notes graphics and I didn’t want to create custom keyboard that will allow user to select only characters that are valid for a file name. I will do this tomorrow.

Regards,
Tomasz

I’ll look into character restriction for the built-in keyboard.

I also recommend you combine the splash window and the main menu window. This way your back image isn’t loaded twice. Simply show and hide the buttons according to the thumbdrive state and move the status label from splash over.

Josh,

Maybe it would be nice to be able to set restrictions specific for selected input data type (e-mail, file name, phone number etc.), but I suppose that it would be better and easier to check the string after tapping ‘done’ (within Glide or with user-made method).

Regards,
Tomasz

Hi,

Sorry for being late a little. Here is the video showing Melody Glider at work: Melody Glider v0.8.9 - YouTube //melody runs at 5:47
As you can see I have to do some improvements and also fix few bugs, what I am doing at the moment :). I cut last seconds after exception occured, but I had some problems while encoding the video, and on second attempt I forgot to cut… ::slight_smile: With next release the video will get better.
And probably the notes should be added in a different way to make it more comfortable and fast in use. I’ll think about it.

Regards,
Tomasz

Very sweet, now replace the peizo with a MIDI synthesizer and you have a professional system!

Yeah, if I had a synth I would try to learn how to handle MIDI protocol. Or maybe… Actually there is a lot of software synthesizers. This will be one of the next steps ;).

Another release ready. Now it loads in less than 7 seconds, thanks a lot Josh! :slight_smile:
http://melodyglider.codeplex.com/releases/view/72255

Things are continuing to look better. I think you can get the load time down more.

EditorWindow loaded in 1944ms
NumericalInputWindow loaded in 1258ms
NoteInputWindow loaded in 1548ms

I would focus on these. I’m sure their load times can be reduced.

One complaint is when you download the ZIP it extracts with two files, I wish they where in one folder called MelodyGlider like it is when you create a project. This makes it easier/cleaner to drop in your project folder.

Now I see something that doesn’t sound nice to me because maybe there will have to be many lines-number-increasing changes. Or maybe won’t, we’ll see.

I was trying to combine DrawDot(), DrawStaccato(), DrawSharp() and DrawFlat() into one method that is using hashtable:

        private bool DrawNote(Note note, int idx)
        {
            if (_editorWindow.XPos + NoteWidth(note) + EditorWindow.CursorWidth > EditorWindow.MelodyFieldBound)
                return false;

            if (note.IsSharp())
                DrawAdditional("Sharp", (int)_pitchLinesY[note.GetPitch().Symbol] + (int)_octaves[note.GetPitch().OctaveShift], idx);
            if (note.IsFlat())
                DrawAdditional("Flat", (int)_pitchLinesY[note.GetPitch().Symbol] + (int)_octaves[note.GetPitch().OctaveShift], idx);
            if (note.IsStaccato())
                DrawAdditional("Staccato", (int)_pitchLinesY[note.GetPitch().Symbol] + (int)_octaves[note.GetPitch().OctaveShift], idx);

            Bitmap next;
            if (note.IsRest())
                next = (Bitmap)_durations[note.GetDuration() + "Rest"];
            else
                next = (Bitmap)_durations[note.GetDuration()];
            
            var noteImg = new Image("Note" + idx, 255, _editorWindow.XPos, (int)_pitchLinesY[note.GetPitch().Symbol] + (int)_octaves[note.GetPitch().OctaveShift], next.Width, next.Height);
            noteImg.Bitmap = next;
            noteImg.TapEvent += _editorWindow.ElementImgTapEvent;

            var backColor = noteImg.Bitmap.GetPixel(0, 0);
            noteImg.Bitmap.MakeTransparent(backColor);

            _relatedWindow.AddChild(noteImg);

            _editorWindow.XPos += next.Width;
            _editorWindow.DisplayedNoteCounter++;
            
            if (note.IsDotted())
                DrawAdditional("Dot", (int)_pitchLinesY[note.GetPitch().Symbol] + (int)_octaves[note.GetPitch().OctaveShift], idx);
            
            return true;
        }

//...

        private readonly Hashtable _additionalResources = new Hashtable
                                                {
                                                    {"Dot", DotData},
                                                    {"Staccato", StaccatoData},
                                                    {"Sharp", SharpData},
                                                    {"Flat", FlatData}
                                                };

        private static readonly ArrayList DotData = new ArrayList { Resources.GetBitmap(Resources.BitmapResources.dotTh), 2, 16, 2 };
        private static readonly ArrayList StaccatoData = new ArrayList { Resources.GetBitmap(Resources.BitmapResources.dotTh), 4, 23, -1 };
        private static readonly ArrayList SharpData = new ArrayList { Resources.GetBitmap(Resources.BitmapResources.sharpTh), 0, 9, 0 };
        private static readonly ArrayList FlatData = new ArrayList { Resources.GetBitmap(Resources.BitmapResources.flatTh), 0, 5, 0 };

        private void DrawAdditional(string name, int noteY, int idx)
        {
            var next = (Bitmap)((ArrayList)_additionalResources[name])[0];
            var dotImg = new Image(name + idx, 255, _editorWindow.XPos + (int)((ArrayList)_additionalResources[name])[1], noteY + (int)((ArrayList)_additionalResources[name])[2], next.Width, next.Height);
            dotImg.Bitmap = next;
            dotImg.TapEvent += _editorWindow.ElementImgTapEvent;

            var backColor = dotImg.Bitmap.GetPixel(0, 0);
            dotImg.Bitmap.MakeTransparent(backColor);

            _relatedWindow.AddChild(dotImg);

            if (name != "Staccato")
                _editorWindow.XPos += next.Width + (int)((ArrayList)_additionalResources[name])[3];
        }

And I was counting ticks inside DrawNote()
And here are the results:
With hashtable:
Drawing only a note - 27ms
Drawing a dotted note - 27ms
Drawing a note with staccato - 60ms
Drawing a sharp note - 66ms
Drawing a flat note - 69ms
Drawing a dotted sharp note - 109ms
Drawing a flat note with staccato - 115ms
Total: 473ms

Without hashtable:
Drawing only a note - 27ms
Drawing a dotted note - 56ms - this is worse, but everything below is better
Drawing a note with staccato - 53ms
Drawing a sharp note - 60ms
Drawing a flat note - 62ms
Drawing a dotted sharp note - 98ms
Drawing a flat note with staccato - 104ms
Total: 460ms

Well, ok… If choosing this particular sequence, total drawing time without hashtables is slightly shorter than with hashtable.
I thought that it the total difference may be bigger, but ok. Now I’m just trying to figure out whether combining four or more functions into one with hashtable is a good manner?

Regards.
Tomasz

Edit:
I think I should try to make DeleteQuestionBox, CancelQuestionBox and NumericalInputWindow to be deleted, and then rectangle with proper content will pop up when needed.