Thursday, February 28, 2008

portamento ...

Retour pas mal d'année en arrière ? Alors que j'essaie d'ajouter les portamento (variation continue de la fréquence d'une des notes) à la bibliothèque ntxm, je me heurte aux même(s) difficulté(s) que lorsque je développais mon player S3M pour mes jeux DOS/Assembleur...

  • Pas évident de structurer les données des channels pour que les effets s'expriment proprement. Là, par exemple, je ne saurais probablement pas gérer la valeur 00 pour les portamento (qui permet de réutiliser la dernière valeur non-nulle).
  • Pas évident non plus de savoir quel est l'effet exact ... d'un effet. autre exemple: mon "portamento up" a une mémoire trop "longue" : au fur et à mesure que le morceau est rejoué, le portamento emmène la note de plus en plus haut au lieu de rejouer toujours do--ré--mi.
edit: au moins, j'ai réussi à avoir des "portamento" qui marchent à la bonne vitesse:
  1. le 'pas' défini par le format XM est "1/256ème d'octave par tick"
  2. la fonction BendNote(note,finetune) de ntxmlib considère qu'il y a 128 niveaux de "finetune" entre deux notes successives (p.ex. C et C#)
  3. le player exécute l'effet "portamento" uniquement sur un "tick". Le nombre de tick par ligne est défini par l'effet "set speed" du morceau. La durée de chaque tick (en millisecondes) est calculée à partir du tempo (en bpm). En clair, si je double le nombre de tick par ligne, le morceau semble défiler plus lentement, mais la même commande "portamento" me conduira deux fois plus loin dans les notes.
oh, just to let you know : portamento up is fixed. I need to reorganize a couple of things in the player to better capture (and manipulate) the "state of a playing sample" (since Sample is simply a static structure that represent "a sample in the module's sound repository"): atm. the new note won't clear the current "drift" of the previous slide (and thus it'll keep on sliding higher and higher).
// our finetune is 12 times finer than the XM 'octave interval'
effstate.actual_finetune[channel]+=param*12;
Instrument *inst = song->instruments[state.channel_instrument[channel]];
inst->bendNote(state.channel_note[channel]+(effstate.actual_finetune[channel]>>7),
state.channel_note[channel],
effstate.actual_finetune[channel]&0x7f,
channel);
break;

Wednesday, February 27, 2008

Beam it, play it, fix it, repeat

I had an argument with the CVS repository last night, but i finally managed to make it accept a new branch with the sources for runme featuring the NTXM player. I hope 0xtob won't be against the re-diffusion of his sources (well, he shouldn't since they're LGPL) ... I am now able to upload any .xm to the DS (up to 512KB) and play it with NTXM. I can also upgrade the software to a new build by just pressing SELECT (and test new effects). All it required was a small rewrite of the XMTransport class so that it works with an (abstract) DataReader rather than plain FILE* ... It even makes it more elegant ^_^

Après moult adverses commandes contre Sieur CVS, m'est avis que la nouvelle branche du projest ustilisant le ménestriciel NTXM estoit fièrement campée. Eh oui. Je vais laisser libmikmod derrière moi et poursuivre avec le code (lgpl) de 0xtob. Je peux donc uploader un .XM (jusqu'à 512KB) sur ma DS puis l'écouter avec NTXM. un p'tit SELECT et c'est le player que je mets à jour (histoire de tester le support de nouveaux effets). ça ne m'aura demander qu'une légère réécriture de XMTransport.

edit: okay, i've got "set tempo/speed" effect added. I also added (untested) offset effect and wrote a small tool that inspect .xm to report what effects they're using... I'm not that happy with the way the player keeps state, anyway. Both "Instrument" and "Sample" classes are used as an "samples database", but nothing capture the current state of a playing note, which makes e.g. offset effect tedious to implement ... I fear similar boring edits to be required when we'll have to support retrig and the like.

Tuesday, February 26, 2008

ntxm->play();

category:modplayerj'ai des petits soucis avec la bibliothèque mikmod qui aurait du servir de soundplayer dans mes jeux. De plus en plus de soucis, en fait ... Du coup, j'ai l'intention de passer à libntxm, le modplayer qui est au coeur de l'excellent NitroTracker de 0xtob, et qui nous fait pleinement profiter des capacités audio de la console (mixage hardware sur 16 canaux).

Le seul hic, c'est que pour l'instant, je n'arrive pas encore à lui faire cracher du son dans runme :( Une fois que ce sera règlé, il me restera à assurer le support des S3M (minimum) et des IT (là, ça va être plus chaud) pour pouvoir profiter des petites musiques du frérot.

Howdy! I got libntxm working in runme this lunch time. I was getting less and less satisfied with libmikmod's quality (corrupted playout buffer) and wanted to switch to hardware mixing instead. This is still a very basic test atm (e.g. just playing a pre-configured XM song when you enter the "beam out" window), but you can expect "play XM received by WiFi" feature within the week ...

Once i get that done, i bet i'll try to write a S3M reader (drawing inspiration from mikmod's source, of course) and add support for S3M effects to the libntxm. That should bring me most of my bros' music library (before he switched to Impulse Tracker -- which will be a higher challenge to deal with) for my games, with minimal CPU load and best possible output quality.

edit: okay. ça marche. J'avais fait l'andouille suprême: contrairement à la bibliothèque libmikmod, libntxm n'utilise *pas* le FIFO interne de la DS pour transmettre ses commandes. On a tout simplement un tableau circulaire dans lequel les commandes successives (e.g. playSong, stopSong, etc.) sont inscrite et que chaque "moitié" du modplayer manipule. Le tout est placé dans une zone de mémoire spéciale (qui sert également pour s'échanger les coordonnées du stylet, et tout ça).

Et pour la petite histoire, la bibliothèque réseau dswifi, elle, utilise encore un autre mécanisme (une zone de transfert dans la RAM principale, mais dont l'adresse est bidouillée pour court-circuiter le cache du processeur). Là, l'ARM7 apprend l'adresse de la structure (allouée côté ARM9) lors d'une phase de dialogue initial à travers le FIFO, et les mises à jour de la structure sont également annoncées "over FIFO". 0xtob, lui, reprenant le code du modplayer posté sur le forum GBAdev, vérifie gentillement si un nouveau message est arrivé tous les 60èmes de secondes (et donc dans le "Vblank" handler plutôt qu'en réponse à un évènement sur le FIFO :P)

Ca y est ? vous êtes perdus ?

Monday, February 25, 2008

Zelda Sound Test

Tout a commencé par une archive que m'avait filé MinishLink : la bande son intégrale de Zelda : Phantom Hourglass. Du coup, je me suis lancé ce week-end dans une frénésie de downloads (principalement sur le très excellent sound-test.org), à grand renfort de plugin "flashgot" pour firefox d'ailleurs.

J'ai toujours trouvé les "autres" zeldas un peu faiblards côté musique par rapport à mon "Link's Awakening fétiche". Le décompte :

  • Zelda : Link to the Past : 30 thèmes, tous les donjons (ou presque) utilisent la même musique
  • Zelda : Link's Awakening : 80 pistes, dont 8 pour les donjons et 8 pour les instruments collectés à la fin de chaque donjon.
  • Zelda : Oracle of xxx : 40 pistes chacun. Il y a aussi une musique séparée pour chaque donjon.
  • Zelda : Occarina of Time : 80 pistes.
  • Zelda : The Minish Cap : 50 pistes
  • Zelda : Phantom Hourglass : près de 70 pistes, mais dont une dizaine servent d'introduction (des thèmes des premiers zeldas joués à 2 instruments)
Bon, la comparaison n'est pas très juste. Je devrais filtrer les pistes qui ne sont que des effets sonores (genre "il reste un trésor" ou "trouvé une petite clé" ...)

edit:
au niveau sonore, c'est la bande son de "Minish Cap" qui me plaît le plus ... Ce mélange "chip+midi" avec quelques samples et des ondes toutes simples pour les basses et le rythme donnent un style absolument unique et parfaitement adapté au jeu. Par contre, le son de la N64, bof bof. Il manque de pèche.
edit++: finalement, je retire les "oracle of xxx" de ma playlist ... Même s'il y a quelques thèmes sympas, je trouve qu'il y a sur-utilisation de square waves (et faire un chiptune tout en squarewave, bof.) ... Elles ne sont pas aussi agréables à écouter que celles de Link's Awakening (mais c'est peut-être dû aux émulateurs qui ont été utilisés pour rendre les .mp3 plus qu'au boulot des musiciens de la "zelda-team", of course).

Saturday, February 23, 2008

Link's Awakening sur DS

Je suis parti dans un trip nostalgique hier (minishlink pourra témoigner), si bien que ce matin, je suis parti à la pèche aux émulateurs Game Boy et GBC pour me refaire les excellents Zelda sorti sur ces petites consoles. A faire tourner sur ma DS, évidemment whistle

Le meilleur que j'aie trouvé jusqu'ici, c'est Lameboy. J'ai aussi essayé DSboy (qui ne supporte apparement pas le GBC) et goomba (pour GBA, que je n'ai pas réussi à démarrer avec ma SuperCard) ... Bref. Aucun d'eux n'a l'air de supporter le son du gameboy, et c'est là que je m'étonne.

Sans le son, un jeu gameboy, c'est franchement insipide ... Je suis d'autant plus surpris que je pensais que ce serait un jeu d'enfant pour une autre console nintendo. J'avais tenté un émulateur GB sur mon PDA (sharp zaurus) il y a quelques années, mais je n'avais pas été très étonné que le son en soit absent (petit CPU et hardware son a priori très différent, tout juste capable de faire du streaming audio).

Bref. Les choses auraient pu en rester là sans Cobain, qui m'a fait remarquer que l'adaptateur Supercard SD intègre un émulateur NES (pocket NES, je pense), un émulateur GB et GBC (Goomba DS, mais une version qui marche ^_^) et même un émulateur Master System (iirc). Et en effet, les fichiers .gb et .gbc sont listés par le menu de démarrage de la supercard!

I have to confess, I've been emulating lots of Nintendo titles while switching millenium. So many NES, SNES and even gameboy titles we had found on the freshly-available Internet made me realise how small the 'supermarkt demonstration kiosk' selection was compared to the international catalogue. And chatting with MinishLink made me wish I could play some gameboy titles again. Preferably on the Nintendo DS.

I tried a few of the suggested homebrew emulators (lameboy, DSboy, goomba), but even the best-working one lacked sound support. And a gameboy title is quite tasteless if you remove sound, imho. Then Cobain pointed out that my Supercard linker does feature a NES and a GB/GBC emulator. Even a Master System emulator!
Things unfortunately go a bit wild when trying to save, especially in Zelda titles.

Ca marche impec (mais j'imagine que les possesseur d'un linker slot 1 auront quand-même besoin d'un émulateur). J'avais cru comprendre que la DS n'avait pas les chips nécessaires pour faire tourner les jeux GBC ... je viens de pousser sur L+R pour tenter une sauvegarde ... Et je tombe sur le menu "Goomba Color alpha 6 on NDS" ... on dirait bien que les cocos de chez Supercard ont embarqué plus que je ne le pensais sur la cartouche ^_^

J'ai pu me refaire un petit "Zelda DX" (version GBC de "Link's Awakening", mon zelda préféré -- auquel il paraît qu'ils auraient rajouté un donjon caché ... me réjouis de le tester). Par contre, sauver est un peu plus complexe:
  1. pressons START+SELECT+A+B pendant le jeu pour écrire l'état de la quête dans la fausse mémoire de sauvegarde de l'émulateur
  2. pressons maintenant L+R pour invoquer le menu de l'émulateur, ce qui l'oblige à copier "fausse mémoire de sauvegarde" dans la "fausse mémoire de sauvegarde" embarquée sur la supercard.
  3. Enfin, appuyons sur "L+R+SELECT+A" pour invoquer la gestion des sauvegarde de la Supercard et sauver ça dans un fichier .sav sur la carte SD.
  4. Sur certains jeux, la dernière étape ne marche pas (je n'ai pas su la faire fonctionner dans Zelda : Oracle of Ages, par exemple). Il faut alors éteindre la console et la rallumer immédiatement après. On voit alors le fichier dans le menu "saver" et on a la possibilité de le copier vers la carte SD (il était en effet resté quelques secondes sur la supercard, même privée d'alim.

Thursday, February 21, 2008

extern "C" { ... }

Dans la série "le monde magique et surprenant du C++", le commandant stdio nous emmène au plus profond de la mer d'incompréhension pour observer le standard (poisson très farouche) dans son milieu naturel ...

on s'accroche bien.

extern "C" {
class X {
X() { iprintf("toto"); }
~X() { iprintf("tutu"); }
void stuut() {iprintf("stuut\a\n");}
};
}

on compile, eh oui. Ca marche. Surpris ? Je viens (dans un fichier C++) de déclarer une classe à l'intérieur d'un bloc que beaucoup considère comme "un truc compatible avec le bon vieux C". Bin détrompez-vous, 'extern "C"' sert uniquement à décider si l'on utilise ou pas le triturage de noms de fonction (en anglais, "name mangling") propre au C++.

Wednesday, February 20, 2008

Pendant ce temps là, sur la Wii

Après un petit "pong", c'est au tour de Tetris d'apparaître en homebrew sur la Wii. Quelqu'un a en effet trouvé une faille dans le jeu Zelda: Twilight Princess qui lui permet d'exécuter le code de son choix, tout ça rien qu'en bidouillant un fichier de sauvegarde stocké sur une carte mémoire SD. Le principe est assez classique: c'est celui du stack overflow qui hante les cauchemars des sysadmins UNIX depuis deux générations. Peu pratique et longuet, j'en conviens, mais personnellement, je trouve l'approche plus élégante que d'aller souder une puce sur le lecteur de disque.

Jouons à Tetris dans Twilight Princess ?

Vous avez une Wii et le jeu "Twilight Princess" ? faites un tour sur http://wiibrew.org/index.php pour en savoir plus et télécharger les petites démos, puis racontez-nous ce que vous en avez pensé dans les commentaires ^_^

Running homebrew on a cartridge-based console usually gets down to finding a PCB that will present custom (and dynamic) contents as if it was legit contents, thanks to custom chips. But what about consoles using optical disks ? Well, one thing you could still do is abuse some existing flaws in existing games so that you force it to run some (bootstrap) code that was made part of innocuous payload. Such tricks are used to bypass securities in many other systems, so it is nice to see it done for fun rather than for havoc or profit, for once.
This is what happens with the 'tetris in twilight princess' exploit. You tweak a savefile (which happen on SD card) so that your horse's name (iirc) triggers a crash, and while crashing, the game's code suddenly start executing your Tetris code. It isn't as convenient as a linker, but I'd definitely better try something like that than soldering wires or custom chips around the optical disk of a console of mine, tbh.

edit: depuis le temps, le "Homebrew Channel" s'est mis en place, qui ne nécessite plus l'emploi de Twilight Princess que pour son "installation". Je n'ai pas eu l'occasion de me familiariser avec son fonctionnement, donc je vous renvoie soit vers les pages proposées par Olivier B. soit vers le blog de mon frère.

BatWindow

Rien avoir avec un personnage de noir vétu qui porte son slip sur la tête dans le ciel de gotham, je vous rassure ... Je testais hier soir une manière assez amusante d'assurer les transferts de répertoires entiers avec runme: des fichiers batch.

J'ai déjà une structure d'interpréteur de commandes ligne par ligne (pour les scripts de jeu), j'en ai juste tiré une variante (héritage et abstraction, hein ^_^) qui supporte d'autre commandes comme "chdir", "mkdir", "wget" ou "sendmsg". Seul le mode de transfer "natif" (avec mon petit protocole) semble poser quelques soucis (encodage des adresses IP, sans doute). Il n'y a pas l'air d'avoir de "inet_aton" dans la bibliothèque NDS, donc je tâtonne à coups de wireshark :P

Quand ça sera fait, je n'aurai plus qu'à modifier le serveur pour qu'il produise le fichier de commande correspondant au répertoire à transférer, et roulez jeunesse ! Comme j'ai aussi une commande "sendmsg" pour envoyer un paquet UDP avec un message convenu, tout va bien : je pourrai signaler au serveur que je veux le fichier suivant ;)

Yesterday evening was a speed-coding evening. I just figured out a funny way to upload full directories in a single click with "runme": batch files. Since the "game script interpreter" component of runme was already doing line-per-line parsing, all i had to do was (virtually) to replace "spr.load" and "bg.load" with "chdir", "mkdir", "wget" (for http transfers) and friends. I also gave the batch language the ability of sending custom strings towards a UDP port and to execute .nds files out of the SD card. Actually, only the 'native' transfer commands aren't working that well. I might have something going wrong with encoding of IP addresses, and the lack of "inet_aton" in the DKP release i'm using doesn't help.

edit: oh, j'oubliais: il y a aussi une commande "exec", donc potentiellement, je pourrais remplacer le téléchargement d'un fichier ".nds" par un .bat qui le sauve puis l'exécute. Pour l'instant, j'écris les .bat d'exécution à la main, ce qui est presque plus lent que de rebooter la DS. Seul point noir, ça ne marche pas avec tous les homebrew (je soupçonne quelque-chose du côté de l'ARM7), et j'ai toujours du mal avec le patch DLDI à la volée...

Monday, February 18, 2008

DSFTP v2.6 -- bugfix release

(vu sur dev-fr.org)

Pour les flemmards du linker bjoern giesler réalise une nouvelle version de "DSFTP", client et serveur FTP pour la DS.
DsFTP, je connais. C'est un des programmes que j'ai essayé avant de me lancer dans la réalisation de "runme". J'ai profité du temps de midi pour faire un peu le point sur cette nouvelle version ...
  • y'a p'têt ben un client, mais pour sûr, l'est pas dans l'zip que vous avez là, ma bonne dame!
  • je seconde minishlink: une accélération de vitesse n'aurait pas été de refus. J'ai fais quelques tests de petits fichiers qui ont traîné à 8KB/sec. En comparaison, mon petit "runme" fait-maison transfère grosso-modo à 90KB.
  • je refais un test sur un fichier de 7Mo. Curieusement, après quelques bytes à 8KB/s, il passe à ~27KB/s. Va comprendre ... Au moins, le fichier est passé complètement.
  • la gestion des répertoires n'est pas ultime. "mkdir FOF -> 202 directory created" "cd FOF -> 550 no such directory" O_o
  • plus de problèmes de stabilité. Ca, c'est un bon point. J'avais cessé d'utiliser la version 2.2 parce que les transfers un peu gros finissaient toujours par crasher le serveur avant d'être finis.
/!\ n'oubliez pas "type binary" en début de session FTP. Sans ça, votre programme va subir des conversion CR-LF potentiellement destructrices. Très mauvais sur les .nds
/!\ toujours la même restriction sur les arm7 custom. vous pouvez faire quote BOOT /path/to/filename.nds une fois le fichier transféré, mais l'ARM7 du serveur FTP restera en place. A moins d'avoir compilé avec le côté "7" par défaut provenant du même devkit que celui de l'auteur, attendez vous à booter votre .nds à la main.

I gave Bjoern's DSFTP tool one more try with the new release. I'm indeed beaming NDS files through wifi more than I'm using SD cards in readers, but sometimes I end up on a software like VGMDS that requires precise directories to be created with some default contents to be found (like spritesheet and tutorials, in this case). my own runme doesn't do that yet, so it seemed to be the perfect use case for trying DSFTP.
Unfortunately, I couldn't change to newly created directories. I could boot uploaded .nds files, but only if they use the same ARM7 code as the FTP server itself. The good thing is that it is clearly more stable than the previous version I used.

En définitive, ça me paraît un excellent outil de maintenance (pour transférer des photos contenues sur la DS, pour uploader le contenu d'un jeu qui demande des fichiers de données par-ci par-là (je pense à VGDMS), même si j'aurais apprécié une commande "mkdir" qui marche vraiment :P
Par contre, pour l'utilisation dans un cycle de développement, je ne le trouve pas encore mûr. le login/mot de passe et le passage en mode "binary" sont pénibles à la longue, et la protection n'est pas énorme à moins d'avoir le WEP sur votre connection : le mot de passe peut sans problème être épié par quelqu'un qui pourra alors se promener sur votre DS sans que vous n'ayez le moyen de le contrer (à part en éteignant la console). Quelques alternatives à retenir : DS2DS de Kram, dsup (http://donotjava.netsons.org/) et bien sûr mon petit runme ... Voilà. Bonne release, donc, mais je continuerai mon développement sur mes outils perso. edit: il faudra que je me trouve un client FTP ubuntu qui supporte la confirmation "all" aux commandes mget et mput. Visiblement, c'est là que le bât blesse :P

Thursday, February 14, 2008

[todo] runme reloaded

"Runme", c'est ma "combox" à moi. Entendez par là un petit outil pour la DS qui permet de se passer de linker et d'accélérer le cycle développement. Il est capable de transférer des fichiers d'un PC vers le répertoire "moving" de la DS à 90KB/s, techniquement capable (également) de transférer des fichiers de la DS vers le PC, mais pour l'heure, je me suis limité au choix des 4 fichiers édités par le Sprite Editor. Côté PC, il faut un programme spécial (petit script perl ou un programme java) pour "offrir" un fichier au téléchargement.

"Runme" is my all-in-one transfer and testing tool on the nintendo DS. The kind of "get-rid-of-your-linker" or "i-lost-my-media-card-reader" tool that is intended to boost software development on the console. It's my favourite way of transferring content from a PC to the console through WiFi at speeds approaching 90KB/s.
With the proper program running on your PC, it can also beam files out of the console (though i don't have a user-friendly interface for this atm).
Over time, it has gathered module player and bare game engine facilities, but it still lacks a couple of features to get a release of its own as "runme: reloaded".

Bref. Il serait temps que je fasse quelque-chose de "releasable" à partir de ce projet . Genre:

  • [wish] faire une version java qui intègre upload et download sur PC.
  • [done] permettre de choisir n'importe quel fichier pour l'exporter hors de la DS
  • [done] choisir le répertoire dans lequel les transferts s'opèrent sur la carte flash (pour l'instant, tout ce passe dans /moving)
  • [wish] prévoir un type "répertoire" pour l'importation vers la DS. Il apparaît comme une simple entrée dans la liste des transferts, mais quand on l'active, il crèe un nouveau répertoire sur la DS, recontacte le serveur et lui demande les fichiers un par un ... Ce serait bien pour tester VGDMS ^_^ (edit: remplacé par un server.pl qui présente les fichiers les uns après les autres).
  • [wish] intégrer les stubs "auto-update" dans la PAlib pour conquérir le monde...
  • [done] m'assurer que le démarrage d'un autre programme marche même lorsque les patches DLDI entrent en jeu.
edit: j'ai re-testé les patches DLDI ce midi. Au moins, le patcheur embarqué est cohérent avec lui-même et le fait que le "stub" qui passe d'un programme à l'autre soit en mémoire vidéo n'affecte pas son bon fonctionnement. Cherchons ailleurs ...
So the todo-list for the runme software include mostly integration of browsing widgets (to pick the import
directory or the exported file), integrate downloader and uploader in a single java program. I also need to support a "directory" transfer type which would make the DS ring back the PC and perform bulk transfers of many files at once (e.g. to test VGDMS).
The ultimate killer feature, though, would be to provide a twisted version of PALib that would be compatible with runme's program booting mechanism, but this means i first need to fix DLDI patcher embedded in the software.

Thursday, February 07, 2008

DirShow & TypeWord

Première difficulté pour le "level editor": la gestion des fichiers. J'avais contourné la difficulté d'une manière assez élégante dans sprite Editor en fixant la limite à quatre fichiers: spriteA, spriteB, spriteX et spriteY. On choisissait celui à charger/sauver en appuyant sur un des boutons de la console au moment voulu.

Ne garder que 4 fichiers modifiables avec soi, ma foi, ce n'est pas bien méchant pour dessiner ses sprites dans le RER ... Mais pour pouvoir éditer jusqu'à 4 jeux, là, ça ne va plus du tout. Chaque jeu ayant ses blocs de sprites, ses maps, ses tiles. Non. Il me fallait une boîte de dialogue "ouvrir" et "sauver" ou qqch comme ça.

C'est chose faite. Un peu rudimentaire, mais rapide d'accès (comparé à mes expériences précédentes avec Nitro Tracker, par exemple), et me donnant les briques de base pour pouvoir "nommer" n'importe quoi d'autre par la suite, et p'têt bien remplacer le "composeur de couleurs" horrible avec un clavier un peu plus "sympa", inspiré de ces claviers alphabétique sur lesquels on compose son nom dans les highscores ...

Le tout pour un encombrement de "seulement" 64x80 pixels. Oui ma bonne dame. Seul petit "truc": j'utilise (comme toujours) le bouton "L" de la console pour faire office de "shift" entre les lettres "paires" et les lettres "impaires". 'faudrait que je brevette ça, tiens ^_^

Bon. 'faudra que j'ajoute ça à "runme", qu'il puisse modifier son répertoire de travail ...
(PS: il y a évidemment des tonnes d'alternatives : http://headkaze.drunkencoders.com/ )

edit: oh! suis-je bête. J'allais oublier de vous pointer vers la démo (parfaitement inutile) et le code ^^"
edit+: pfiouh. J'essaye d'extraire le code "commun" à runme et SEDS (en particulier, tous les widgets et les routines de gestion des fichiers .spr) dans une bibliothèque. Mais comme je viens de changer la définition de base de la classe Widget, y'a du boulot ... et y'aura du debugging ... Mais bon, ça devrait valoir le coup.