My MeeGo projects [update 1]
A couple of months ago, Nokia send me and large number of other amateur/pro developers each a N950 on loan so we could do some serious MeeGo coding. So what do I have to show for so far? Well, not much at the moment but I have a couple of interesting projects in the pipeline…
The published stuff
These humble apps are what I have published on Ovi Store or on Nokia developers forums so far:
| SystemInfo | SensorInfo | CuteBrain | AirControl |
| System information tool | Sensor information tool | Memory game | Soundboard example (and don’t you dare mention fart app!) |
[update 1] Then I put together this measuring app in a few hours:
| cuteMeter |
| Simple digital ruler |
I also did a quick and dirty mini-port of sdlcave to Harmattan, in case you missed that ![]()
| sdl cave |
| Old N900 game? |
The current projects
These are projects on my current TODO list. Not all will be released of course. Note that the extremely ugly mock up graphics will be cleaned up if ever released
| MeeGoSweden app | TågInfo | Unnamed QML game | “Pling” |
| Community app, probably will have to scrap this one |
Swedish real-time train information app | Wait for it… | Otomota clone and more |
VemRingde: “Who is calling” Swedish app. I am currently stuck trying to figure out how I access phone and call log functions from Qt.
And then we have the library projects which take most of my time right now:
| SDL42 library | Audio42 library |
| Simple scene-graph game engine on top of SDL | Real-time audio synthesis library for N9 |
Then there are these projects, which I hope to finish as soon as the above libraries get stable enough:
| What | Use | Notes |
| DrumPad | Virtual drums | real-time sound generation, multi touch |
| MPU | Music “programming” | audio “programming” app with its own powerful “audio CPU“ |
| Thememin42 | Theremin app | more real-time noise… |
| SameSame | Same Game clone | Port from J2ME |
The future projects
These are on my “maybe later” list. That is, what I would love to do but will probably never have the time for ![]()
| What | Use | Notes |
| LightSaber | time waster | real-time sound generation + sensors |
| Unnamed guitar app | Play guitar | real-time sound generation, multi touch, possibly using acceleration sensors |
| Brickade2 | Lights off clone | Port from J2ME |
| Unnamed game1 | RTS mini game | Probably a port of my Android game “Domi” |
| Unnamed game 2 | Tower defense game | |
| Unnamed game 3 | Hitori clone | |
| Unnamed game 4 | Puzzle game | Lets call it a Jewel-like puzzle game… |
Well, that’s about it! Now, I would love to see what everyone else on #N950Club are doing with their phones.
Image manipulation with J2ME, part 5
Ok, this will be a very short post about addition of a single function to imagelib. But first, please note that Imagelib has moved to a new home: You can find the latest version of imagelib at Nokia Developer Forums (NDF). You are welcome to examine the source code, discuss it with others and even make changes.
Performance issues
Due to lack of GPU and/or slow virtual machines, J2ME phones are generally slow at drawing images on the screen. This usually leads to bad performance in, for example, games.
Images with transparent backgrounds are especially slow on J2ME phones that lack real GPUs. I have therefore added a simple function that removes the transparent pixels from images. This should hopefully lead to better performance:
Image ImageUtils.setBackground(Image src, int color)
I have also extended the imagelib demo with a performance test for transparent / opaque images. I used the following test image (which is actually the spritesheet from SameSame):
On a Sony Ericsson W890 (unfortunately, the only working J2ME I have right now) I get the following numbers:
| Original transparent image | Opaque Image | Opaque Image on GPU | |
| drawing time for N images [ms] |
260 |
85 |
85 |
While we are at it, lets also benchmark the difference between ImageUtils.moveToCPU() and ImageUtils.moveToGPU(). This is what I got on a 200×247 image on the same phone:
| Original image [as returned by Image.createImage() ] | Moved to CPU | Moved to GPU | |
| drawing time N images [ms] |
1500 |
1500 |
1300 |
tl;dr summary
- If you don’t need transparent images, don’t use them as they are much slower than opaque images. To create an opaque image from a transparent one, use ImageUtils.setBackground()
- If you explicitly move your images to GPU, you will achieve slightly better drawing performance.
The new code has been committed to NDF repository. Have fun!
Leaderboards are (mostly) back online…
As you might have noticed, the leaderboards for SameSame, Brickade2 and my new MeGoo toy game “CuteBrain” have been down for a couple of days. After some heavy re-writing of the server code, they are now back online and should work without any problems [until the next time Google screws up]..
The Technical stuff
If you are interested in the technical details, please read on. If you are not, you can safely ignore the rest of this post.
Why the leaderboards stopped working
The leaderboards are organized as tables in a database running on Google’s cloud computing service, the App Engine. I pay nothing for these particular servers since the amount of computation needed for the leaderboards is (was) well below Google’s daily free quote.
However, a few weeks back Google changed they way they compute their free quota. With the new system, you would get up to 50.000 database fetches for free. Above that you would have to pay Google. While 50.000 may sound a lot, it is actually an extremely small number. In fact, due to Google’s very inefficient database implementation, it is barely enough to look up a single players position in the leaderboard:
SELECT COUNT(*) from samesame_table where score > your_score
Sine this table has around 60.000 entries, the database will have to iterate over 60.000 rows to compute your position. With the new quota system, one such lookup is already above your daily free quota.
How we fixed the leaderboard
With the new quota system, the leaderboards would have cost us around USD 3.000 / year to run. This is simply too much for a hobby project. Besides, you can buy and run your own server for much less.
A much cheaper solution was to re-write the leaderboard software to avoid the expensive database operations. This is exactly what we did:
Use Memcache instead of Datastore
To avoid the expensive database operations, we added the a caching mechanism where common queries are stored to avoid further database lookups. So Instead of always doing a database lookup like this
// SELECT COUNT(*) from samesame_table where score > your_score PersistenceManager pm = ... Query q = pm.newQuery(SameSame.class, “this.score > score”); q.setResult(“COUNT(*)”); q.declareParameters(“Long score”); Object count = q.executeWithArray(your_score);
We would do something like this
import com.google.appengine.api.memcache.*;
...
MemcahceService service = MemcacheServiceFactory.getMemcacheService();
Object count = service.get(“your_position_” + your_score); // is it already cached?
if(count == null) {
PersistenceManager pm = …
Query q = pm.newQuery(SameSame.class, “this.score > score”);
q.setResult(“COUNT(*)”);
q.declareParameters(“Long score”);
Object count = q.executeWithArray(your_score);
service.put(“your_position_” + your_score, count); // save it for later use
}
Limit Datastore use even further
With the Memcache, once the caches are filled the number of database accesses will decrease significantly. Our next problem was that since the free quota was set so extremely low, it was not even enough for a single database query. Hence we could never get as far as filling the cache with data.
A small hack we used to get past this was to limit the query size to a subset of the database. Since the rows are fetched in batches of 100, we limited the query size to 99:
Query q = pm.newQuery(SameSame.class, “this.score > score”); q.setRange(0, 99); ...
While this is not always correct, it was the only way to get thing working. With this hack in place, we can now (barely)run the servers within the free quota ![]()
Cleanup your database!
We have also added a daily cron job which cleans the database by removing the lowest ranking entries. This will hopefully shrink the SameSame table a bit since there are a number of total n00b scores in there ![]()
Client side changes
A new client app will be introduced soon, which will refuse to submit your score to leaderboard if your score is very low or if it has not increased since the last update.
Lessons learned
If there is anything to be learned from all this is that you should never trust your cloud provider. They can screw up and they can screw up badly, and they have no problems charging your credit card for their mistakes.
The leaderboards are down
Sorry everyone, all leaderboards (and some other on-line functions) are currently down. The problem is not at your end. It is not even at my end. It is at Google’s who once again has screwed up badly.
Google?
Yes, the leaderboards run on Googles cloud computing service, which they call App Engine.
To make a *very* long story short, Google is changing their payment system and their latest changes seem to have broken something in their quota system because they claim that the very first leaderboard access that one of you guys made today has filled my entire quota for 24 hours:
Until Google resolves this problem the leaderboards are disabled.
RIP dmr
/* * This is a tribute to Dennis Ritchie (aka dmr), * creator of UNIX and C, who passed away this week. */ #include < stdio.h > int main(void) { printf("Hello, Heaven!!\n"); return(0); }
A friendly remainder to SameSame players around the world…
I am very happy that people are still playing SameSame. And to show you my appreciation I have added the global scoreboard and a lot of new levels lately.
I am however a little annoyed by the amount of SPAM on the scoreboard. Please do not use an URL as your player-id. If you do that, your score will be removed. The server has a function to detect and remove all such spam, it can even blacklist your IP. If I see more spam, I will have to turn on the anti-spam function.
Thank you in advance,
AV
SystemInfo, a simple MeeGo utility
I have had my N950 for exactly two weeks and despite being on vacation and all that I already have a number of interesting projects going on for it
Let publish our first MeeGo app
Just to test the waters I wrote and published a very simple app called “SystemInfo”, which is a simple utility app for showing various types of informations about your new shiny MeeGo device
I sent the binaries to Nokia for publishing and got it accepted after about 48 hours.
My N950 just got its Store software activated and when I logged in I noticed my little app right on the front page:
|
|
When I have more time, I will write more about the whole experience. For now you can find the app source code (C++ and QML) on the Nokia developers site (GPPLv3) and the binaries on the Nokia Ovi Store.Where to get it
Power of QML: here is a minimal twitter app [updated]
Few days ago, I received a Nokia N950 developer phone from Nokia (thanks guys!). This is what I found on the box:

The N950 is a prototype/developer device for those who want to write apps for Meego/Maemo/Harmattan/Qt and the upcoming Nokia N9. The text on the box is a QML application for twitter. You can run this code on the phone, but you can also run the code on PC:
|
If you write in your username and password and press “Send to twitter” [but make sure you read the security warning on the end of this post first] , you will see this appearing on your twitter account:
The code snippet is of course there to show developers the power of QML. I have played a little with QML since I got the phone and while things are still at beta state, I have to admit that QML is very powerful. It is also extremly simple to integrate QML and C++.
Security warning!!
In order to keep the code simple, Nokia has moved out the twitter API logic to their own web server. When you press “Send to twitter”, the app will actually send your username/password to a server in Finland (not nokia.com) which will take care of the rest. Are you comfortable with sending your twitter credentials to an unknown server, in plain?
If not, I suggest you do as I did: change your password to something stupid, send the tweet and then change back to your real password.
Atmel AVR transfer bit: is anyone else using it??
Am I the only one doing this sort of stuff on Atmel AVR?
write_dac: ; data in r23, r22 is zero ldi r21, 8 wdb_1: ; update data bst r23, 7 ; MSb rol r23 bld r22, DAC_DATA out PORTB, r22 ; clock in: sbi PORTB, DAC_BCK cbi PORTB, DAC_BCK ; loop stuff subi r21, 1 brne wdb_1 ret
This code is bit-banging I2S to some DAC. It uses the T-flag (AKA the transfer bit) in an ATTiny11 to avoid conditional jumps. I see it as a poor mans substitute for ARMs conditional execution
Oh, did I mention that some of these little AVRs are plenty powerful?
Dear computer, we need to talk…
Back in the days, when men where men and wrote their own device drivers… I got bored and wrote an RSS-reader in C# instead.
Now, I know what you thinking. “So what, everyone has done that! It’s like the first assignment on Internet Programming 101″. But you know, my RSS-reader was “special”.
Can your RSS-reader really read???
You see, my RSS-reader didn’t simply download a bunch of XML files from the internet and showed them on the screen. My reader actually… hmm… READ the news to me. I had it running in background and once in a while it would download a new feed and then you would hear the creepy voice of Microsoft Sam saying something like
“SLASH-DOT DOT ORG … COLON… will the year TWO ZERO ZERO TWO … finally be the year of LI-NUU-X on the desktop … QUESTION MARK” [yeah, they have ran that story every year since 1992]
It was fun, geeky and kinda creepy at the same time, and got really annoying after 2-3 minutes.
Microsoft speech synthesis in .NET
I found a backup disk with my old code repository on it, and browsing the old code [oh.. the nostalgia] I was amazed how simple speech synthesis was in .NET. I found that virtually all code related to speech in my RSS-reader was written in a single class:
using System;
using System.Collections;
using System.Threading;
using SpeechLib;
public class Talk {
private ArrayList voices;
private SpVoice voice;
private bool talking;
public int Rate {
set { if(value < 10 && value > -10) voice.Rate = value; }
get { return voice.Rate; }
}
public bool Talking {
get { return talking; }
}
public ArrayList Voices {
get { return voices; }
}
public Voice Voice {
set { voice.Voice = (SpObjectToken)value.Speaker; }
}
public Talk() {
voice = new SpVoice();
voice.Rate = 0;
voice.EndStream += new _ISpeechVoiceEvents_EndStreamEventHandler(talk_done);
talking = false;
voices = new ArrayList();
foreach (ISpeechObjectToken x in voice.GetVoices("", ""))
voices.Add( new Voice(x.GetDescription(0), x) );
}
public void Say(String s) {
Stop();
talking = true;
voice.Speak(s, SpeechVoiceSpeakFlags.SVSFDefault
| SpeechVoiceSpeakFlags.SVSFlagsAsync);
}
public void Stop() {
bool tmp = talking;
for(int i = 0; (i < 5) && talking; i++) {
voice.Skip("Sentence", 10000000); // UGLY, UGLY HACK
Thread.Sleep(200);
}
if(tmp) Thread.Sleep(1000);
}
private void talk_done(int StreamNumber, object StreamPosition)
{
talking = false;
}
}
This tiny class gets amazing amount of stuff done. Not only it talks, you also can enumerate voices and change voice and pitch. It also does some book keeping for you to avoid "double talk".
Anyway, to get this code running you will need three additional things:
- .NET binding for the speech library. In my case, I used "Interop.SpeechLib.dll".
- The Voice class not shown here, you just have to figure it out by yourself.
- Perhaps something interesting to say??
Have fun!



