It has been 2 weeks... With the job searches and a nice flu, I didn't progressed as fast as expected, but I have at least finished the "editor" part of the editor. Here is what have been added since the last time :

Magnetism Screenshot_2013-02-27-15-53-03.png

Notes are glued on a circle division (a circle has 16 divisions) and on a beat division. Each beat can be divided in 1, 2, 3, 4, 6, 8, 12 or 16 divisions with the slider on the left.


Anchors allows to handle tempo and signature (number of beats per measure) variation. I allowed the selection of only 3 different signatures : 3/4, 4/4, 5/4 to simplify the GUI and because by playing with the division size, it's possible to reproduce different signatures. For instance :

  1. 6/4, 6/8, etc... => 3/4
  2. 2/2, 2/4, 4/8, etc... => 4/4
  3. 10/4, 5/8, etc... => 5/4 (not really used in modern music, but it's possible to encounter it one day or another, so better implement it now)

I faced 2 issues when I implemented anchor edition :

Event dependency

In my data model, every event (note or anchor) is dependent of the previous anchor, has a reference to this one and vice-versa. When we need to change the anchors order, the child anchor become parent of its parent anchor and vice-versa, and for a short time during the "switch" algorithm, an anchor could have 2 child anchors, which triggered an infinite loop. I first enforced the model to be sure that every anchor could have only one child anchor, by throwing an exception once a second anchor is added. But that leaded to an "hyper-static" model : each event has a mandatory parent anchor (which is essential to compute its exact time position), and it wasn't possible to switch 2 anchors at all. So, I transformed this constraint into an assertion at th end of the switch algorithm and I could simply debug the algorithm.

Moral: don't put to much constraints on the data model.

Position format

For obvious space reasons, song positions are stored with only an Int thank to scala value classes (I'll explain this concept in another post) and were encoded like this :

| measure | division |
| 16 bits | 16 bits  |

measure is the measure index and division the note position into the measure. For instance, if division = 16384 : 16384/65536 = 1/4, so the note start at 1/4 from the measure beginning. The main issue is that if we start editing a song and later we notice that the song is not in 4/4 but in 3/4, changing signature will move every note by "compressing" them. I had to recode position depending on the beat instead of the measure. This way, we can change signature without moving notes.

| beat    | division |
| 16 bits | 16 bits  |

But that leaded to another issue : with 2^16 beats, the maximum represented duration is relatively short : at 200 BPM the maximum duration is of 5.46 minutes. I increased the number of bits for the beat representation, but by diminishing the number of bits for the division we also reduce the precision. For intance, at 200 BPM and with 8 bits for the division, each division has a duration of 1.17 ms which is really acceptable, but at 10 BPM, the precision diminished to 23.44 ms, which is now not acceptable. So I had to find a bits repartition in a way that the maximum duration is enough long at high BPM and with a acceptable precision at low BPM. Finally, I splited the integer this way :

| beat    | division |
| 20 bits | 12 bits  |

It give a maximum duration of 87.38 minutes at 200 BPM and a division precision of 1.46 ms at 10 BPM, a good compromise !

Edition panels

3 edition panels which are accessible by touching an element (which will then appear highlighted):

  1. song.png Song : used to edit the main anchor and the song offset
  2. note.png Note : used to edit the note angle and position
  3. anchor.png Anchor : used to edit the anchor BPM, signature and position

What took me most of the time, was building every edition component and moreover improving the engine touch event management.

But, these panel pointed out the first limits of the engine : since I mix geometric shapes and text, I have to often switch the openGL shader, which cause an FPS drop... For now, the performance still remains acceptable so I will prioritize functionalities over performances and go on with the game development. And once I have a playable game, I'll go back to the engine improvement.

Other things

  1. Double-tap on edit buttons : the 3 buttons of the left (add, move and delete) have 2 modes : note et anchor. We tap one time to activate note mode and two time for the anchor mode. And to reduce manipulation errors : the mode is only active while the button is pressed. It will avoid us to modify a note if we instead only wanted to move into the song.
  2. Zoom limits
  3. Position limits
  4. Automatic deletion of identical events

Nothing really complicated.


The next step is now to add a play mode into the editor and then a game mode. Once it will be done, I'll let you test all of it : :)